六边形架构在Go中依赖包组织与依赖流向:domain层严禁引入infra或handler包,仓储接口须定义在domain/ports下,application仅依赖domain接口,adapter实现端口并只导入infra和domain,Wire注入须按infra→adapter→application→handler顺序。

六边形架构在 Go 里不是开箱即用的框架,而是靠包组织、接口位置和依赖流向决定的——domain 包里出现 sql.DB 或 gin.Context,就说明已经失败了。
domain 层不能 import 任何 infra 或 handler 包
这是六边形架构的硬性红线。只要 domain 目录下 import 了 "github.com/go-redis/redis/v9"、"database/sql" 或 "github.com/gin-gonic/gin",整个架构就失效了。
- 所有仓储接口(如
OrderRepository)必须定义在domain/ports或domain/repository下,且该包不能有外部依赖 - 领域实体(如
Order、User)只能含纯数据和业务方法,不带数据库标签或 JSON 字段名 - 如果测试时发现无法 mock 仓储——大概率是接口和实现混在同一个包,或者 service 构造函数直接接收
*sql.DB
application 层只依赖 domain 接口,不碰具体实现
application 是业务逻辑的执行中枢,它调用 domain 的接口,但绝不感知底层技术细节。它的结构体字段应全是接口类型,不是具体客户端。
- 服务构造函数参数必须是接口:例如
func NewOrderService(repo domain.OrderRepository) *OrderService,而不是repo *postgres.OrderRepo - 不要在
application里做数据转换(比如把map[string]interface{}转成domain.Order),那是 adapter 的事 - gRPC 或 HTTP handler 不该出现在
application目录里;它们属于外层适配器,只负责解析请求、调用 application service、序列化响应
adapter 层实现端口,且只 import infra 和 domain
adapter(或叫 infra)是翻译层:把领域接口调用,转成具体技术操作。它可 import database/sql、go.mongodb.org/mongo-driver/mongo,但绝不能 export 领域模型以外的类型。
立即学习“go语言免费学习笔记(深入)”;
- 一个典型适配器结构:
type orderRepo struct { db *sqlx.DB },它实现domain.OrderRepository接口,方法签名完全一致 - HTTP handler 中不要直接 new service,而应通过 DI 注入已构造好的 service 实例;否则会把
sqlx.DB一路透传进 handler - 若用
wire,provider 必须按依赖方向声明:先声明 infra 组件(如sqlx.DB),再声明 adapter(如postgres.OrderRepo),最后才是 application service
Wire 注入顺序错,整个架构就塌一半
wire 本身不强制架构,但它能暴露依赖错误。如果 wire.Build 里先写 application.NewOrderService,再写 postgres.NewOrderRepo,wire 会报 unresolved dependency——因为 service 依赖 repo,但 repo 还没被提供。
- 正确顺序必须是:infra 组件 → adapter 实现 → application service → handler
- 每个 provider 函数返回类型必须精确匹配其依赖项的接口类型,比如
func provideOrderRepo(db *sqlx.DB) domain.OrderRepository - 别在
wire.go里 importhandler包来构建 server;handler 应该只接收已注入的 service,自身不参与 DI 图
最常被忽略的是:领域接口的 error 类型是否统一、context 是否贯穿到底、以及 gRPC 方法签名里有没有偷偷塞进 grpc.Server 或 protoreflect.MethodDescriptor ——这些都会让 domain 变成“纸糊的内核”。


















