读gRPC Microservices in Go第四章

六边形架构也称端口和适配器系统。用端口和适配器创建了一个抽象层,隔离了app的核心和外部依赖
对于六边形架构,以下文件夹在Go项目中很常见:
- application: 包含微服务业务逻辑,指代业务实体的领域模型和向其他模块公开核心功能的API组合
- port: 包含核心应用程序与第三方之间集成的合同信息。可以是关于访问核心应用功能的合同,或关于指定数据库系统可用功能的合同(如果用于持久层)
- adapter —— 包含使用在端口中定义的合同的具体实现。如gRPC可以是一个适配器,具有处理请求并使用API端口访问核心功能的具体实现
- 比如一个app具有一些功能,并将其暴露给客户。功能可以是
CreateProduct、GetProduct等,可通过REST、gRPC和其他适配器将它们暴露给客户,这些适配器将使用这些功能的端口层定义的合同
- 比如一个app具有一些功能,并将其暴露给客户。功能可以是
go mod init接受一个VCS URL来准备依赖结构。当你将这个模块作为另一个项目的依赖添加时,该项目将从你提供的模块初始化VCS解析可用标签
先实现应用核心,后实现外层更加容易。如Web或CLI层依赖于应用层
order.go
package domain
import (
"time"
)
type OrderItem struct {
ProductCode string `json:"product_code"` # 产品的唯一代码
UnitPrice float32 `json:"unit_price"` # 单个产品的价格
Quantity int32 `json:"quantity"` # 产品的数量
}
type Order struct {
ID int64 `json:"id"` # 订单的唯一标识符
CustomerID int64 `json:"customer_id"`# 订单的拥有者
Status string `json:"status"` # 订单的状态
OrderItems []OrderItem `json:"order_items"`# 订单中购买的物品列表
CreatedAt int64 `json:"created_at"` # 订单创建时间
}
func NewOrder(customerId int64, orderItems []OrderItem) Order { # 创建默认订单的函数
return Order{
CreatedAt: time.Now().Unix(),
Status: "Pending",
CustomerID: customerId,
OrderItems: orderItems,
}
}api.go
package api
import (
"github.com/huseyinbabal/microservices/order/internal/application/core/domain" # 订单域对象的包
"github.com/huseyinbabal/microservices/order/internal/ports" # DB适配器的端口
)
type Application struct {
db ports.DBPort # API依赖于DBPort
}
func NewApplication(db ports.DBPort) *Application {
return &Application{
db: db, # 在应用初始化时传递DBPort
}
}
func (a Application) PlaceOrder(order domain.Order) (domain.Order, error) {
err := a.db.Save(&order) # 通过DB端口保存订单
if err != nil {
return domain.Order{}, err
}
return order, nil
}internal/ports/api.go
package ports
import "github.com/huseyinbabal/microservices/order/internal/application/core/domain"
type APIPort interface {
PlaceOrder(order domain.Order) (domain.Order, error)
}internal/ports/api.go
package ports
import "github.com/huseyinbabal/microservices/order/internal/application/core/domain"
type DBPort interface {
Get(id string) (domain.Order, error) // 通过其唯一ID获取Order
Save(*domain.Order) error // 将Order领域保存到数据库
}GORM是Go世界中非常流行的ORM库
internal/adapters/db/db.go
package db
import (
"fmt"
"github.com/huseyinbabal/microservices/order/internal/application/core/domain"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
type Order struct {
gorm.Model // ❶ 添加结构体元数据,如ID
CustomerID int64
Status string
OrderItems []OrderItem // ❷ 引用OrderItem
}
type OrderItem struct {
gorm.Model
ProductCode string
UnitPrice float32
Quantity int32
OrderID uint // ❸ 回引Order模型
}嵌入GORM来标记一个结构体为领域实体,通过在结构体中添加.Model。这样可以为你的领域模型增加内置字段,如ID、CreatedAt、UpdatedAt和DeletedAt。
实现DB适配器来保存和获取此应用程序中的订单信息,让我们看看如何引入gRPC作为另一个适配器。
12因素应用程序鼓励你:
- 使用声明性设置来配置基础设施和应用程序环境自动化,以便快速部署到任何环境,如开发环境、预发布环境或生产环境。
- 在底层操作系统之间建立清晰的契约,使得同一个应用程序可以在不同参数的任何环境上执行。
- 使用持续部署来最小化环境之间的差异。
- 轻松扩展系统而无需任何重大更改。
订单应用程序需要以下环境变量才能正常工作:
-
ENV——用于区分生产环境和非生产环境。例如,你可以在非生产环境中启用调试级别的日志,并在生产环境中使用信息级别。
-
DATA_SOURCE_URL——指的是数据库连接URL。
-
APPLICATION_PORT——订单服务将在其上提供服务的端口。
-
六边形架构帮助你隔离微服务中的层,以实现可测试和清晰的应用程序。
-
端口用于定义层之间的契约,而适配器是可以插入端口的具体实现,使核心应用程序可供终端用户使用。
-
首先实现应用程序核心,然后继续外层是有帮助的。
-
GORM是Go的ORM库,为数据库相关操作提供了良好的抽象。
-
十二因素应用程序在微服务中具有良好的用例,即应用程序配置可以通过环境变量传递,并且你可以根据环境配置它们。
-
六边形架构中的层组合是通过依赖注入完成的。
-
grpcurl提供了类似cURL的行为,通过调用gRPC端点来处理订单数据。