跳转到主内容
websoft网络软件专家 - 深耕网络技术,打造实用软件!

Go语言怎么做六边形架构_Go语言六边形架构教程【简明】

六边形架构在Go中核心是划清三道依赖线:领域层禁用适配器、端口接口须定义在domain或infra、DI入口必须位于adapter层;目录隔离重于结构模板,gRPC需作为驱动适配器而非领域延伸,Wire需严查指针返回与显式绑定。 六边形架构在 Go 里不是“搭架子”,而是划清三道线 Go 项目用六边形架构,核心不是目录建得多整齐,而是靠三道不可逾越的依赖线把业务逻辑护住:领域层 不能 import 任何适配器 (比如
github.com/go-sqlite/sqlite3
、
google.golang.org/grpc
)、端口接口必须定义在领域层或 infra 层(不能藏在
adapter/repository
里)、Wire 或其他 DI 工具的
inject.go
文件必须落在适配器层——这是唯一能同时看到领域接口和具体实现的地方。 常见错误现象:
domain/order_service.go
直接
import "gorm.io/gorm"
,后续加 Redis 缓存或换 PostgreSQL 就得改业务代码 正确做法:在
domain/repository.go
定义
type OrderRepository interface { Save(ctx context.Context, o *Order) error }
,让
adapter/repository/mysql_order_repo.go
去实现它 Wire 的
InitializeApp()
函数必须放在
cmd/
或
adapter/server/
下,否则生成的依赖图会绕过端口约束 目录结构别硬套模板,先守住 domain/ 和 adapter/ 的物理隔离 很多团队卡在第一步,是因为照抄 “domain/aggregate/entity” 这类子目录,结果把
po.Order
(数据库表结构)和
domain.Order
(含业务规则的实体)混在同一个包里,或者让
adapter/controller
直接 new 出
domain.OrderService
—— 这等于把六边形画成了实心圆。 domain/ 下只放:聚合根(
order.Aggregate
)、值对象(
money.Money
)、领域服务接口(
order.PaymentService
)、DTO(
order.CreateOrderRequest
) adapter/ 下分两块:
controller/
(接收 HTTP 请求、校验、转成 domain.DTO)、
repository/
(实现 domain.Repository 接口,用 SQL 或 gRPC 调用外部服务) infra/ 是可选缓冲区:放
infra/db/sqlx_client.go
、
infra/mq/kafka_producer.go
等“纯技术组件”,它们被 repository 适配器调用,但 domain 层完全看不见 gRPC 服务怎么当好“驱动适配器”,而不是入侵领域层 gRPC 不是领域模型的延伸,它是外部系统驱动你业务的一条通道。把它当“HTTP 的替代品”来用,就很容易把
proto
文件里的 message 直接当 domain 实体用,导致领域逻辑被 protobuf 序列化规则绑架。 go语言参考手册 中文CHM版 Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。本文给大家带来Go参考手册,需要的可以来下载! Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。 Go 语言特色 简洁、快速、安全 并行、有趣、开源 内存管理、v数组安全、编译 下载 真实使用场景:前端调 gRPC 创建订单 →
adapter/server/order_grpc_server.go
接收
CreateOrderRequest
→ 转成
domain.CreateOrderCommand
→ 交给
domain.OrderApplicationService
执行 关键参数差异:
proto
中的
repeated string tags
在 domain 层应映射为
Tags []string
,但校验逻辑(如长度 ≤5)必须写在 domain 层,不能靠 proto 的
validate = true
注解 性能影响:如果在 gRPC handler 里直接调
repo.Save()
并返回
status.CodeOK
,那失败时无法区分是 DB 连接超时还是业务规则不满足;必须统一转成 domain.Error 类型再由适配器映射为 gRPC status Wire 生成依赖时最常漏掉的两个检查点 Wire 不报错不等于依赖正确。它只保证类型能对上,不管语义是否越界。很多项目跑通了,一加测试就 panic,问题往往出在这两处。 立即学习 “ go语言免费学习笔记(深入) ”; 检查
Provide
函数的返回值是否带指针:错误写法
func NewDB() sql.DB
(值类型),正确写法
func NewDB() (*sql.DB, error)
—— Wire 要求所有 provider 必须返回指针或 error,否则注入的是副本,连接池失效 检查
Inject
函数的参数顺序:如果
func InitializeGRPCServer(repo OrderRepository, svc OrderService)
,而
OrderService
内部又依赖
OrderRepository
,Wire 默认不会递归解析,必须显式用
wire.Bind(new(OrderRepository), new(mysqlRepo))
绑定实现 兼容性坑:
wire.Build
里若引用了
testutil.NewInMemoryRepo()
,上线时没删干净,会导致生产环境用内存库覆盖 MySQL,且无日志提示 真正难的不是画出六边形,是每次加一个新功能时,都得亲手把新代码往 domain/ 里塞、把胶水代码往 adapter/ 里扔、把技术细节推进 infra/ —— 没有自动化能替你做这个判断。

相关文章