读gRPC Microservices in Go第四章

读gRPC Microservices in Go第四章

六边形架构也称端口和适配器系统。用端口和适配器创建了一个抽象层,隔离了app的核心和外部依赖

对于六边形架构,以下文件夹在Go项目中很常见:

  • application: 包含微服务业务逻辑,指代业务实体的领域模型和向其他模块公开核心功能的API组合
  • port: 包含核心应用程序与第三方之间集成的合同信息。可以是关于访问核心应用功能的合同,或关于指定数据库系统可用功能的合同(如果用于持久层)
  • adapter —— 包含使用在端口中定义的合同的具体实现。如gRPC可以是一个适配器,具有处理请求并使用API端口访问核心功能的具体实现
    • 比如一个app具有一些功能,并将其暴露给客户。功能可以是CreateProductGetProduct等,可通过REST、gRPC和其他适配器将它们暴露给客户,这些适配器将使用这些功能的端口层定义的合同

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端点来处理订单数据。