前言

Kratos 是一个 Go 语言实现的微服务框架,近期正在用 Kratos 做实训,也是我最早接触微服务实践的项目。

初期读项目结构深感无力,花了一段时间了解 DDD 设计,才慢慢搞明白项目和业务结构 orz。

关于 DDD 的知识,可以(存疑)参考我上一篇文章:DDD 架构

项目结构

若直接使用 kratos cli 创建项目,将得到基于官方 kratos-layout 的项目结构:

.
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── api // 下面维护了微服务使用的proto文件以及根据它们所生成的go文件
│   └── helloworld
│   └── v1
│   ├── error_reason.pb.go
│   ├── error_reason.proto
│   ├── error_reason.swagger.json
│   ├── greeter.pb.go
│   ├── greeter.proto
│   ├── greeter.swagger.json
│   ├── greeter_grpc.pb.go
│   └── greeter_http.pb.go
├── cmd // 整个项目启动的入口文件
│   └── server
│   ├── main.go
│   ├── wire.go // 我们使用wire来维护依赖注入
│   └── wire_gen.go
├── configs // 这里通常维护一些本地调试用的样例配置文件
│   └── config.yaml
├── generate.go
├── go.mod
├── go.sum
├── internal // 该服务所有不对外暴露的代码,通常的业务逻辑都在这下面,使用internal避免错误引用
│ ├── biz // 业务逻辑的组装层,类似 DDD 的 domain 层,data 类似 DDD 的 repo,而 repo 接口在这里定义,使用依赖倒置的原则。
│   │   ├── README.md
│   │   ├── biz.go
│   │   └── greeter.go
│   ├── conf // 内部使用的config的结构定义,使用proto格式生成
│   │   ├── conf.pb.go
│   │   └── conf.proto
│   ├── data // 业务数据访问,包含 cache、db 等封装,实现了 biz 的 repo 接口。我们可能会把 data 与 dao 混淆在一起,data 偏重业务的含义,它所要做的是将领域对象重新拿出来,我们去掉了 DDD 的 infra层。
│   │   ├── README.md
│   │   ├── data.go
│   │   └── greeter.go
│   ├── server // http和grpc实例的创建和配置
│   │   ├── grpc.go
│   │   ├── http.go
│   │   └── server.go
│   └── service // 实现了 api 定义的服务层,类似 DDD 的 application 层,处理 DTO 到 biz 领域实体的转换(DTO -> DO),同时协同各类 biz 交互,但是不应处理复杂逻辑
│   ├── README.md
│   ├── greeter.go
│   └── service.go
└── third_party // api 依赖的第三方proto
├── README.md
├── google
│   └── api
│   ├── annotations.proto
│   ├── http.proto
│   └── httpbody.proto
└── validate
├── README.md
└── validate.proto

Kratos 没有完全照搬传统的 DDD 分层,而是做了一些更适合工程实践的调整。不过我们依然可以将其与标准的 DDD 概念对应起来,帮助理解。

Kratos 的核心思想是:将业务逻辑与技术细节分离,并将业务逻辑集中在 biz 层(即 DDD 的领域层)。它通过依赖倒置,让上层(biz)定义接口,下层(data)实现接口,从而保护核心业务逻辑的纯粹性。

重要组成

(1) cmd
这是应用的启动入口和依赖组装部分。
cmd/main.go:负责初始化、启动和停止应用,它调用 wire.go 生成的代码来构建一个完整可运行的应用。
cmd/wire.go:使用 Google Wire 进行依赖注入的配置。它定义了如何将各个层(internal/serverinternal/serviceinternal/bizinternal/data)的组件像搭积木一样组装成一个完整的应用。

可以对应 DDD 基础设施层的启动和组装部分。

(2) internal/server
负责创建和处理网络协议,不包含任何业务逻辑。

创建 HTTP 和 gRPC 服务器实例,配置路由、中间件(如认证、日志、限流)。提供将请求路由到 service 层的对应方法。

可以对应 DDD 基础设施层的接口适配器部分,将外部的网络请求转化为对内部应用服务的调用。

(3) internal/service
应用服务层,是用例的入口点。它负责协调任务,但不实现核心业务规则。实现了在 api/ 目录下由 Protobuf 定义的 gRPC/HTTP 服务接口。

一般职责:

  • 参数校验(DTO 验证)
  • 事务控制
  • 调用 biz 层的领域对象或服务,以完成一个具体的业务用例
  • 数据转换(将来自外部的 DTO 转换为 biz 层能理解的领域对象,并将 biz 层返回的领域对象转换为对外响应的 DTO)

可以对应 DDD 应用层,真正的业务逻辑在 biz 层。

(4) internal/biz
业务逻辑的核心与组装层,是 Kratos 项目中最重要的部分。

包含:实体、聚合根、值对象、领域服务、仓储接口、领域事件等

biz 层定义它需要的数据访问方法(如 UserRepo),但不关心具体实现。使用依赖倒置原则。
这里只包含业务逻辑,完全不知道数据是如何持久化的,也不知道谁在调用它(HTTP还是gRPC)。

可以对应 DDD 领域层(核心)。

(5) internal/data
偏重仓储业务,负责具体的技术实现。实现了在 biz 层定义的仓储接口。

具体工作包括:

  • 与数据库交互
  • 使用缓存(Redis)
  • 调用其他微服务(通过 gRPC)
  • 将数据库中的 PO(Persistent Object,持久化对象,如数据表行)转换为 biz 层理解的领域对象,反之亦然。

可以对应 DDD 基础设施层。

(6) internal/conf
定义了基础设施的元数据,即基础设施的形态,不直接实现功能。

可以认为是 DDD 基础设施层的配置基础。


更详细的描述,可以直接阅读 Kratos 官方的开发文档,放在参考资料里供读者使用。

参考资料:

Kratos 项目结构:https://go-kratos.dev/zh-cn/docs/intro/layout/
Kratos:Go工程化 - Project Layout 最佳实践:https://go-kratos.dev/zh-cn/blog/kratos/go-project-layout/