該文章為學習開源微服務框架kratos的學習筆記!官方文檔見:簡介 | Kratos
Kratos 一套輕量級 Go 微服務框架,包含大量微服務相關框架及工具。
一、Kratos 項目結構簡介
通過 Kratos 工具生成的?Go工程化項目模板如下:
application
|____api
| |____helloworld
| | |____v1
| | |____errors
|____cmd
| |____helloworld
|____configs
|____internal
| |____conf
| |____data
| |____biz
| |____service
| |____server
|____test
|____pkg
|____go.mod
|____go.sum
|____LICENSE
|____README.md
二、kratos 依賴注入關系圖
?其中有關依賴注入的詳細文檔見:Go工程化 - 依賴注入 | Kratos
以下是我自己總結的kratos依賴注入關系圖:
特別注意:data層的 NewXxxRepo 返回的是 biz 層定義的實體數倉的接口類型!!!
這樣做的目的:正常情況是 data 層定義好數據操作函數后被 biz 層調用,但這里是 biz 層定義好操作數據層的接口,然后讓 data 層去實現,從而實現 data 層對 biz 層的反向依賴。這樣做的好處是方便 data 層重構(比如數據存儲由 mysql 改為 sqlServer 等),而不需要修改任何 biz 層的代碼。
//下面代碼位于 data/article.go
// 注意返回參數為 biz 層的接口,ArticleRepo 需要實現 biz.ArticleRepo 接口
func NewArticleRepo(data *Data, logger log.Logger) biz.ArticleRepo {return &articleRepo{data: data,log: log.NewHelper(logger),}
}// 下面代碼位于 biz/article.go
// 在 biz 層定義好數據操作層(data層)的接口,以便讓 data 層實現,不管 data 層今后如何實現或重構,都不影響 biz 層的業務代碼
type ArticleRepo interface {// dbListArticle(ctx context.Context) ([]*Article, error)GetArticle(ctx context.Context, id int64) (*Article, error)CreateArticle(ctx context.Context, article *Article) errorUpdateArticle(ctx context.Context, id int64, article *Article) errorDeleteArticle(ctx context.Context, id int64) error
}
三、依賴注入生成的代碼實例
運用 google/wire 工具將上述依賴注入生成具體的kratos項目代碼示例:
原始 wire.go 代碼:
// initApp init kratos application.
func initApp(*conf.Server, *conf.Data, *conf.Auth, log.Logger) (*kratos.App, func(), error) {panic(wire.Build(server.ProviderSet, data.ProviderSet, biz.ProviderSet, service.ProviderSet, newApp))
}
?工具生成的代碼wire_gen.go:
// initApp init kratos application.
func initApp(confServer *conf.Server, confData *conf.Data, auth *conf.Auth, logger log.Logger) (*kratos.App, func(), error) {dataData, cleanup, err := data.NewData(confData, logger)if err != nil {return nil, nil, err}articleRepo := data.NewArticleRepo(dataData, logger)articleUsecase := biz.NewArticleUsecase(articleRepo, logger)blogService := service.NewBlogService(articleUsecase, logger)userRepo := data.NewUserRepo(dataData, logger)encryptService := biz.NewEncryptService(auth)accountUseCase := biz.NewAccountUseCase(logger, auth, userRepo, encryptService)accountService := service.NewAccountService(logger, accountUseCase)httpServer := server.NewHTTPServer(confServer, logger, blogService, accountService)grpcServer := server.NewGRPCServer(confServer, logger, blogService, accountService)app := newApp(logger, httpServer, grpcServer)return app, func() {cleanup()}, nil
}