Files
tyapi-server/internal/container/container.go
2025-07-21 15:13:26 +08:00

523 lines
16 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package container
import (
"context"
"fmt"
"time"
"go.uber.org/fx"
"go.uber.org/zap"
"gorm.io/gorm"
"tyapi-server/internal/application/certification"
"tyapi-server/internal/application/finance"
"tyapi-server/internal/application/product"
"tyapi-server/internal/application/user"
"tyapi-server/internal/config"
domain_certification_repo "tyapi-server/internal/domains/certification/repositories"
domain_finance_repo "tyapi-server/internal/domains/finance/repositories"
finance_service "tyapi-server/internal/domains/finance/services"
domain_product_repo "tyapi-server/internal/domains/product/repositories"
product_service "tyapi-server/internal/domains/product/services"
user_service "tyapi-server/internal/domains/user/services"
"tyapi-server/internal/infrastructure/cache"
"tyapi-server/internal/infrastructure/database"
certification_repo "tyapi-server/internal/infrastructure/database/repositories/certification"
finance_repo "tyapi-server/internal/infrastructure/database/repositories/finance"
product_repo "tyapi-server/internal/infrastructure/database/repositories/product"
"tyapi-server/internal/infrastructure/external/ocr"
"tyapi-server/internal/infrastructure/external/sms"
"tyapi-server/internal/infrastructure/external/storage"
"tyapi-server/internal/infrastructure/http/handlers"
"tyapi-server/internal/infrastructure/http/routes"
shared_database "tyapi-server/internal/shared/database"
"tyapi-server/internal/shared/esign"
"tyapi-server/internal/shared/events"
"tyapi-server/internal/shared/health"
"tyapi-server/internal/shared/hooks"
sharedhttp "tyapi-server/internal/shared/http"
"tyapi-server/internal/shared/interfaces"
"tyapi-server/internal/shared/logger"
"tyapi-server/internal/shared/metrics"
"tyapi-server/internal/shared/middleware"
sharedOCR "tyapi-server/internal/shared/ocr"
"tyapi-server/internal/shared/resilience"
"tyapi-server/internal/shared/saga"
sharedStorage "tyapi-server/internal/shared/storage"
"tyapi-server/internal/shared/tracing"
"tyapi-server/internal/shared/validator"
domain_user_repo "tyapi-server/internal/domains/user/repositories"
user_repo "tyapi-server/internal/infrastructure/database/repositories/user"
"github.com/redis/go-redis/v9"
)
// Container 应用容器
type Container struct {
App *fx.App
}
// NewContainer 创建新的应用容器
func NewContainer() *Container {
app := fx.New(
// 配置模块
fx.Provide(
config.LoadConfig,
),
// 基础设施模块
fx.Provide(
// 日志器 - 提供自定义Logger和*zap.Logger
func(cfg *config.Config) (logger.Logger, error) {
logCfg := logger.Config{
Level: cfg.Logger.Level,
Format: cfg.Logger.Format,
Output: cfg.Logger.Output,
FilePath: cfg.Logger.FilePath,
MaxSize: cfg.Logger.MaxSize,
MaxBackups: cfg.Logger.MaxBackups,
MaxAge: cfg.Logger.MaxAge,
Compress: cfg.Logger.Compress,
}
return logger.NewLogger(logCfg)
},
// 提供普通的*zap.Logger用于大多数场景
func(log logger.Logger) *zap.Logger {
if zapLogger, ok := log.(*logger.ZapLogger); ok {
return zapLogger.GetZapLogger()
}
// 如果类型转换失败创建一个默认的zap logger
defaultLogger, _ := zap.NewProduction()
return defaultLogger
},
// 数据库连接
func(cfg *config.Config, cacheService interfaces.CacheService, logger *zap.Logger) (*gorm.DB, error) {
dbCfg := database.Config{
Host: cfg.Database.Host,
Port: cfg.Database.Port,
User: cfg.Database.User,
Password: cfg.Database.Password,
Name: cfg.Database.Name,
SSLMode: cfg.Database.SSLMode,
Timezone: cfg.Database.Timezone,
MaxOpenConns: cfg.Database.MaxOpenConns,
MaxIdleConns: cfg.Database.MaxIdleConns,
ConnMaxLifetime: cfg.Database.ConnMaxLifetime,
}
db, err := database.NewConnection(dbCfg)
if err != nil {
return nil, err
}
// 设置GORM缓存插件
if err := SetupGormCache(db.DB, cacheService, cfg, logger); err != nil {
logger.Warn("GORM缓存插件设置失败", zap.Error(err))
// 不返回错误,允许系统在没有缓存的情况下运行
}
return db.DB, nil
},
// Redis客户端
NewRedisClient,
// 缓存服务
fx.Annotate(NewRedisCache, fx.As(new(interfaces.CacheService))),
// 事件总线
// 提供workerCount参数
func() int {
return 5 // 默认5个工作协程
},
events.NewMemoryEventBus,
fx.Annotate(events.NewMemoryEventBus, fx.As(new(interfaces.EventBus))),
// 健康检查
health.NewHealthChecker,
// 提供 config.SMSConfig
func(cfg *config.Config) config.SMSConfig {
return cfg.SMS
},
// 提供 config.AppConfig
func(cfg *config.Config) config.AppConfig {
return cfg.App
},
// 事务管理器
func(db *gorm.DB, logger *zap.Logger) *shared_database.TransactionManager {
return shared_database.NewTransactionManager(db, logger)
},
// 短信服务
sms.NewAliSMSService,
// 存储服务
fx.Annotate(
func(cfg *config.Config, logger *zap.Logger) *storage.QiNiuStorageService {
return storage.NewQiNiuStorageService(
cfg.Storage.AccessKey,
cfg.Storage.SecretKey,
cfg.Storage.Bucket,
cfg.Storage.Domain,
logger,
)
},
fx.As(new(sharedStorage.StorageService)),
),
// OCR服务
fx.Annotate(
func(cfg *config.Config, logger *zap.Logger) *ocr.BaiduOCRService {
return ocr.NewBaiduOCRService(
cfg.OCR.APIKey,
cfg.OCR.SecretKey,
logger,
)
},
fx.As(new(sharedOCR.OCRService)),
),
// e签宝服务
func(cfg *config.Config) *esign.Client {
esignConfig, err := esign.NewConfig(
cfg.Esign.AppID,
cfg.Esign.AppSecret,
cfg.Esign.ServerURL,
cfg.Esign.TemplateID,
)
if err != nil {
panic(fmt.Sprintf("e签宝配置创建失败: %v", err))
}
return esign.NewClient(esignConfig)
},
),
// 高级特性模块
fx.Provide(
// 提供TracerConfig
func(cfg *config.Config) tracing.TracerConfig {
return tracing.TracerConfig{
ServiceName: cfg.App.Name,
ServiceVersion: cfg.App.Version,
Environment: cfg.App.Env,
Endpoint: cfg.Monitoring.TracingEndpoint,
SampleRate: cfg.Monitoring.SampleRate,
Enabled: cfg.Monitoring.TracingEnabled,
}
},
tracing.NewTracer,
metrics.NewPrometheusMetrics,
metrics.NewBusinessMetrics,
resilience.NewWrapper,
resilience.NewRetryerWrapper,
saga.NewSagaManager,
hooks.NewHookSystem,
),
// HTTP基础组件
fx.Provide(
sharedhttp.NewResponseBuilder,
validator.NewRequestValidator,
sharedhttp.NewGinRouter,
),
// 中间件组件
fx.Provide(
middleware.NewRequestIDMiddleware,
middleware.NewSecurityHeadersMiddleware,
middleware.NewResponseTimeMiddleware,
middleware.NewCORSMiddleware,
middleware.NewRateLimitMiddleware,
NewRequestLoggerMiddlewareWrapper,
middleware.NewJWTAuthMiddleware,
middleware.NewOptionalAuthMiddleware,
middleware.NewAdminAuthMiddleware,
middleware.NewTraceIDMiddleware,
middleware.NewErrorTrackingMiddleware,
NewRequestBodyLoggerMiddlewareWrapper,
),
// 仓储层 - 用户域
fx.Provide(
// 用户仓储 - 同时注册具体类型和接口类型
fx.Annotate(
user_repo.NewGormUserRepository,
fx.As(new(domain_user_repo.UserRepository)),
),
// 企业信息仓储 - 同时注册具体类型和接口类型
fx.Annotate(
user_repo.NewGormEnterpriseInfoRepository,
fx.As(new(domain_user_repo.EnterpriseInfoRepository)),
),
// 短信验证码仓储 - 同时注册具体类型和接口类型
fx.Annotate(
user_repo.NewGormSMSCodeRepository,
fx.As(new(domain_user_repo.SMSCodeRepository)),
),
),
// 仓储层 - 认证域
fx.Provide(
// 认证命令仓储
fx.Annotate(
certification_repo.NewGormCertificationCommandRepository,
fx.As(new(domain_certification_repo.CertificationCommandRepository)),
),
// 认证查询仓储
fx.Annotate(
certification_repo.NewGormCertificationQueryRepository,
fx.As(new(domain_certification_repo.CertificationQueryRepository)),
),
),
// 仓储层 - 财务域
fx.Provide(
// 钱包仓储
fx.Annotate(
finance_repo.NewGormWalletRepository,
fx.As(new(domain_finance_repo.WalletRepository)),
),
// 用户密钥仓储
fx.Annotate(
finance_repo.NewGormUserSecretsRepository,
fx.As(new(domain_finance_repo.UserSecretsRepository)),
),
),
// 仓储层 - 产品域
fx.Provide(
// 产品仓储 - 同时注册具体类型和接口类型
fx.Annotate(
product_repo.NewGormProductRepository,
fx.As(new(domain_product_repo.ProductRepository)),
),
// 产品分类仓储 - 同时注册具体类型和接口类型
fx.Annotate(
product_repo.NewGormProductCategoryRepository,
fx.As(new(domain_product_repo.ProductCategoryRepository)),
),
// 订阅仓储 - 同时注册具体类型和接口类型
fx.Annotate(
product_repo.NewGormSubscriptionRepository,
fx.As(new(domain_product_repo.SubscriptionRepository)),
),
),
// 领域服务
fx.Provide(
user_service.NewUserManagementService,
user_service.NewUserAuthService,
user_service.NewSMSCodeService,
user_service.NewEnterpriseService,
product_service.NewProductManagementService,
product_service.NewProductSubscriptionService,
// 认证域的领域服务已经整合到应用服务中
finance_service.NewFinanceService,
),
// 应用服务
fx.Provide(
// 用户应用服务 - 绑定到接口
fx.Annotate(
user.NewUserApplicationService,
fx.As(new(user.UserApplicationService)),
),
// 认证应用服务 - 绑定到接口
fx.Annotate(
certification.NewCertificationApplicationService,
fx.As(new(certification.CertificationApplicationService)),
),
// 财务应用服务 - 绑定到接口
fx.Annotate(
finance.NewFinanceApplicationService,
fx.As(new(finance.FinanceApplicationService)),
),
// 产品应用服务 - 绑定到接口
fx.Annotate(
product.NewProductApplicationService,
fx.As(new(product.ProductApplicationService)),
),
// 分类应用服务 - 绑定到接口
fx.Annotate(
product.NewCategoryApplicationService,
fx.As(new(product.CategoryApplicationService)),
),
// 订阅应用服务 - 绑定到接口
fx.Annotate(
product.NewSubscriptionApplicationService,
fx.As(new(product.SubscriptionApplicationService)),
),
),
// HTTP处理器
fx.Provide(
// 用户HTTP处理器
handlers.NewUserHandler,
// 认证HTTP处理器
handlers.NewCertificationHandler,
// 财务HTTP处理器
handlers.NewFinanceHandler,
// 产品HTTP处理器
handlers.NewProductHandler,
// 产品管理员HTTP处理器
handlers.NewProductAdminHandler,
),
// 路由注册
fx.Provide(
// 用户路由
routes.NewUserRoutes,
// 认证路由
routes.NewCertificationRoutes,
// 财务路由
routes.NewFinanceRoutes,
// 产品路由
routes.NewProductRoutes,
// 产品管理员路由
routes.NewProductAdminRoutes,
),
// 应用生命周期
fx.Invoke(
RegisterLifecycleHooks,
RegisterMiddlewares,
RegisterRoutes,
),
)
return &Container{App: app}
}
// Start 启动容器
func (c *Container) Start() error {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
return c.App.Start(ctx)
}
// Stop 停止容器
func (c *Container) Stop() error {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
return c.App.Stop(ctx)
}
// RegisterLifecycleHooks 注册生命周期钩子
func RegisterLifecycleHooks(
lifecycle fx.Lifecycle,
logger *zap.Logger,
) {
lifecycle.Append(fx.Hook{
OnStart: func(context.Context) error {
logger.Info("应用启动中...")
return nil
},
OnStop: func(context.Context) error {
logger.Info("应用关闭中...")
return nil
},
})
}
// RegisterMiddlewares 注册中间件
func RegisterMiddlewares(
router *sharedhttp.GinRouter,
requestID *middleware.RequestIDMiddleware,
security *middleware.SecurityHeadersMiddleware,
responseTime *middleware.ResponseTimeMiddleware,
cors *middleware.CORSMiddleware,
rateLimit *middleware.RateLimitMiddleware,
requestLogger *middleware.RequestLoggerMiddleware,
traceIDMiddleware *middleware.TraceIDMiddleware,
errorTrackingMiddleware *middleware.ErrorTrackingMiddleware,
requestBodyLogger *middleware.RequestBodyLoggerMiddleware,
) {
router.RegisterMiddleware(requestID)
router.RegisterMiddleware(security)
router.RegisterMiddleware(responseTime)
router.RegisterMiddleware(cors)
router.RegisterMiddleware(rateLimit)
router.RegisterMiddleware(requestLogger)
router.RegisterMiddleware(traceIDMiddleware)
router.RegisterMiddleware(errorTrackingMiddleware)
router.RegisterMiddleware(requestBodyLogger)
}
// RegisterRoutes 注册路由
func RegisterRoutes(
router *sharedhttp.GinRouter,
userRoutes *routes.UserRoutes,
certificationRoutes *routes.CertificationRoutes,
financeRoutes *routes.FinanceRoutes,
productRoutes *routes.ProductRoutes,
productAdminRoutes *routes.ProductAdminRoutes,
cfg *config.Config,
logger *zap.Logger,
) {
router.SetupDefaultRoutes()
// 注册所有路由
userRoutes.Register(router)
certificationRoutes.Register(router)
financeRoutes.Register(router)
productRoutes.Register(router)
productAdminRoutes.Register(router)
// 打印注册的路由信息
router.PrintRoutes()
// 启动HTTP服务器
go func() {
addr := ":" + cfg.Server.Port
logger.Info("正在启动HTTP服务器", zap.String("addr", addr))
if err := router.Start(addr); err != nil {
logger.Error("HTTP服务器启动失败", zap.Error(err))
}
}()
}
// ================ 中间件包装函数 ================
// NewRequestLoggerMiddlewareWrapper 创建请求日志中间件包装器
func NewRequestLoggerMiddlewareWrapper(logger *zap.Logger, cfg *config.Config, tracer *tracing.Tracer) *middleware.RequestLoggerMiddleware {
return middleware.NewRequestLoggerMiddleware(logger, cfg.App.IsDevelopment(), tracer)
}
// NewRequestBodyLoggerMiddlewareWrapper 创建请求体日志中间件包装器
func NewRequestBodyLoggerMiddlewareWrapper(logger *zap.Logger, cfg *config.Config, tracer *tracing.Tracer) *middleware.RequestBodyLoggerMiddleware {
return middleware.NewRequestBodyLoggerMiddleware(logger, cfg.App.IsDevelopment(), tracer)
}
// ================ Redis相关工厂函数 ================
// NewRedisClient 创建Redis客户端
func NewRedisClient(cfg *config.Config, logger *zap.Logger) (*redis.Client, error) {
client := redis.NewClient(&redis.Options{
Addr: cfg.Redis.GetRedisAddr(),
Password: cfg.Redis.Password,
DB: cfg.Redis.DB,
PoolSize: cfg.Redis.PoolSize,
MinIdleConns: cfg.Redis.MinIdleConns,
DialTimeout: cfg.Redis.DialTimeout,
ReadTimeout: cfg.Redis.ReadTimeout,
WriteTimeout: cfg.Redis.WriteTimeout,
})
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_, err := client.Ping(ctx).Result()
if err != nil {
logger.Error("Redis连接失败", zap.Error(err))
return nil, err
}
logger.Info("Redis连接已建立")
return client, nil
}
// NewRedisCache 创建Redis缓存服务
func NewRedisCache(client *redis.Client, logger *zap.Logger, cfg *config.Config) interfaces.CacheService {
return cache.NewRedisCache(client, logger, "app")
}
// NewTracedRedisCache 创建带追踪的Redis缓存服务
func NewTracedRedisCache(client *redis.Client, tracer *tracing.Tracer, logger *zap.Logger, cfg *config.Config) interfaces.CacheService {
return tracing.NewTracedRedisCache(client, tracer, logger, "app")
}