Files
tyapi-server/internal/container/container.go
2025-07-28 13:47:58 +08:00

643 lines
20 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"
"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"
certification_service "tyapi-server/internal/domains/certification/services"
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/external/westdex"
"tyapi-server/internal/infrastructure/external/yushan"
"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/payment"
"tyapi-server/internal/shared/resilience"
"tyapi-server/internal/shared/saga"
"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"
api_app "tyapi-server/internal/application/api"
domain_api_repo "tyapi-server/internal/domains/api/repositories"
api_service "tyapi-server/internal/domains/api/services"
api_repo "tyapi-server/internal/infrastructure/database/repositories/api"
)
// 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,
LogDir: cfg.Logger.LogDir,
MaxSize: cfg.Logger.MaxSize,
MaxBackups: cfg.Logger.MaxBackups,
MaxAge: cfg.Logger.MaxAge,
Compress: cfg.Logger.Compress,
UseDaily: cfg.Logger.UseDaily,
}
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,
)
},
),
// 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.Config, error) {
return esign.NewConfig(
cfg.Esign.AppID,
cfg.Esign.AppSecret,
cfg.Esign.ServerURL,
cfg.Esign.TemplateID,
&esign.EsignContractConfig{
Name: cfg.Esign.Contract.Name,
ExpireDays: cfg.Esign.Contract.ExpireDays,
RetryCount: cfg.Esign.Contract.RetryCount,
},
&esign.EsignAuthConfig{
OrgAuthModes: cfg.Esign.Auth.OrgAuthModes,
DefaultAuthMode: cfg.Esign.Auth.DefaultAuthMode,
PsnAuthModes: cfg.Esign.Auth.PsnAuthModes,
WillingnessAuthModes: cfg.Esign.Auth.WillingnessAuthModes,
RedirectUrl: cfg.Esign.Auth.RedirectURL,
},
&esign.EsignSignConfig{
AutoFinish: cfg.Esign.Sign.AutoFinish,
SignFieldStyle: cfg.Esign.Sign.SignFieldStyle,
ClientType: cfg.Esign.Sign.ClientType,
RedirectUrl: cfg.Esign.Sign.RedirectURL,
},
)
},
// e签宝服务
func(esignConfig *esign.Config) *esign.Client {
return esign.NewClient(esignConfig)
},
// 支付宝支付服务
func(cfg *config.Config) *payment.AliPayService {
config := payment.AlipayConfig{
AppID: cfg.AliPay.AppID,
PrivateKey: cfg.AliPay.PrivateKey,
AlipayPublicKey: cfg.AliPay.AlipayPublicKey,
IsProduction: cfg.AliPay.IsProduction,
NotifyUrl: cfg.AliPay.NotifyURL,
ReturnURL: cfg.AliPay.ReturnURL,
}
return payment.NewAliPayService(config)
},
),
// 高级特性模块
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,
// WestDexService - 需要从配置中获取参数
func(cfg *config.Config) *westdex.WestDexService {
return westdex.NewWestDexService(
cfg.WestDex.URL,
cfg.WestDex.Key,
cfg.WestDex.SecretId,
cfg.WestDex.SecretSecondId,
)
},
func(cfg *config.Config) *yushan.YushanService {
return yushan.NewYushanService(
cfg.Yushan.URL,
cfg.Yushan.APIKey,
cfg.Yushan.AcctID,
)
},
sharedhttp.NewGinRouter,
),
// 中间件组件
fx.Provide(
middleware.NewRequestIDMiddleware,
middleware.NewSecurityHeadersMiddleware,
middleware.NewResponseTimeMiddleware,
middleware.NewCORSMiddleware,
middleware.NewRateLimitMiddleware,
NewRequestLoggerMiddlewareWrapper,
middleware.NewJWTAuthMiddleware,
middleware.NewOptionalAuthMiddleware,
middleware.NewAdminAuthMiddleware,
middleware.NewDomainAuthMiddleware,
middleware.NewTraceIDMiddleware,
middleware.NewErrorTrackingMiddleware,
NewRequestBodyLoggerMiddlewareWrapper,
),
// 仓储层 - 用户域
fx.Provide(
// 用户仓储 - 同时注册具体类型和接口类型
fx.Annotate(
user_repo.NewGormUserRepository,
fx.As(new(domain_user_repo.UserRepository)),
),
// 短信验证码仓储 - 同时注册具体类型和接口类型
fx.Annotate(
user_repo.NewGormSMSCodeRepository,
fx.As(new(domain_user_repo.SMSCodeRepository)),
),
// 用户信息仓储 - 同时注册具体类型和接口类型
fx.Annotate(
user_repo.NewGormEnterpriseInfoRepository,
fx.As(new(domain_user_repo.EnterpriseInfoRepository)),
),
// 合同信息仓储 - 同时注册具体类型和接口类型
fx.Annotate(
user_repo.NewGormContractInfoRepository,
fx.As(new(domain_user_repo.ContractInfoRepository)),
),
),
// 仓储层 - 认证域
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.Annotate(
certification_repo.NewGormEnterpriseInfoSubmitRecordRepository,
fx.As(new(domain_certification_repo.EnterpriseInfoSubmitRecordRepository)),
),
),
// 仓储层 - 财务域
fx.Provide(
// 钱包仓储
fx.Annotate(
finance_repo.NewGormWalletRepository,
fx.As(new(domain_finance_repo.WalletRepository)),
),
// 钱包交易记录仓储
fx.Annotate(
finance_repo.NewGormWalletTransactionRepository,
fx.As(new(domain_finance_repo.WalletTransactionRepository)),
),
// 充值记录仓储
fx.Annotate(
finance_repo.NewGormRechargeRecordRepository,
fx.As(new(domain_finance_repo.RechargeRecordRepository)),
),
// 支付宝订单仓储
fx.Annotate(
finance_repo.NewGormAlipayOrderRepository,
fx.As(new(domain_finance_repo.AlipayOrderRepository)),
),
),
// 仓储层 - 产品域
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)),
),
// 产品API配置仓储 - 同时注册具体类型和接口类型
fx.Annotate(
product_repo.NewGormProductApiConfigRepository,
fx.As(new(domain_product_repo.ProductApiConfigRepository)),
),
),
// API域仓储层
fx.Provide(
fx.Annotate(
api_repo.NewGormApiUserRepository,
fx.As(new(domain_api_repo.ApiUserRepository)),
),
fx.Annotate(
api_repo.NewGormApiCallRepository,
fx.As(new(domain_api_repo.ApiCallRepository)),
),
),
// 领域服务
fx.Provide(
user_service.NewUserAggregateService,
user_service.NewUserAuthService,
user_service.NewSMSCodeService,
user_service.NewContractAggregateService,
product_service.NewProductManagementService,
product_service.NewProductSubscriptionService,
product_service.NewProductApiConfigService,
finance_service.NewWalletAggregateService,
finance_service.NewRechargeRecordService,
certification_service.NewCertificationAggregateService,
certification_service.NewEnterpriseInfoSubmitRecordService,
),
// API域服务层
fx.Provide(
api_service.NewApiUserAggregateService,
api_service.NewApiCallAggregateService,
api_service.NewApiRequestService,
),
// API域应用服务
fx.Provide(
api_app.NewApiApplicationService,
),
// 应用服务
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)),
),
// 产品API配置应用服务 - 绑定到接口
fx.Annotate(
product.NewProductApiConfigApplicationService,
fx.As(new(product.ProductApiConfigApplicationService)),
),
// 分类应用服务 - 绑定到接口
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,
// API Handler
handlers.NewApiHandler,
),
// 路由注册
fx.Provide(
// 用户路由
routes.NewUserRoutes,
// 认证路由
routes.NewCertificationRoutes,
// 财务路由
routes.NewFinanceRoutes,
// 产品路由
routes.NewProductRoutes,
// 产品管理员路由
routes.NewProductAdminRoutes,
// API路由
routes.NewApiRoutes,
),
// 应用生命周期
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,
apiRoutes *routes.ApiRoutes,
cfg *config.Config,
logger *zap.Logger,
) {
router.SetupDefaultRoutes()
// api域名路由
apiRoutes.Register(router)
// 所有域名路由路由
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")
}