理解六边形架构-一个简单的Springboot实现

理解六边形架构-一个简单的Springboot实现

六边形架构由AlistairCockburn于2005年提出,其背后的主要思想是在设计软件应用程序时将领域逻辑与外部组件隔离——外部组件必须通过端口和适配器来访问领域逻辑。六边形架构因此也被称为端口-适配器架构。

image

六边形架构风格以业务逻辑为核心的方式组织逻辑视图。应用具备一个或多个入站适配器,而不是表示层,入站适配器通过调用端口来调用业务逻辑处理外部的请求。同样的,应用具备一个或多个出站适配器,而不是数据持久层,出站适配器由业务逻辑中的出站端口调用,来调用外部系统(mysql,redis,zk等等) 。

使用这种方法,系统将通过定义良好的接口在domain层内外进行通信,而无需依赖于实现细节。

Example

让我们实现一个简单的商品服务来理解六边形结构。该商品服务主要提供两个Restful接口:

  1. 创建产品
  2. 通过产品id来获取产品信息

我们首先创建application层、infrastructure层和domain层,代码结构如下:
image-1655824892579

Application层

Application层包含数据流入和流出领域层的端口实现
image-1655824936230
我们在input包里面定义了用例,确定了用户能通过应用做什么。在我们的应用中,用户可以创建商品并通过id来获取商品信息。
此外,我们在output包来连接外部组件。在我们的应用中,使用 ProductOutputPort 来连接数据库获取数据,使用ProductEventPublisher来发送一个商品创建的事件。

Infrastructure层

Infrastructure层是使用适配器表示的六边形架构对外部部分。适配器只能使用input和output端口来与领域层交互。
我们将infrastructure.adapters包分作3部分:

  1. config:用来注册bean
  2. input:通过调用对应的用例(即application层的input port)来驱动整个应用
  3. output:提供application层的output port的具体实现,比如链接db、链接消息队列等

image-1655825633715

Domain层

Domain层是处理业务逻辑的模块,是应用的核心。Domain层与Application层和Infrastructure层完全解耦,因此除业务需求发生更改外,其他层中的变动对Domain层没有任何影响。
image-1655996445024

ProductService是Domain层最核心的类,它实现了Application层input包下的端口,使用output端口(具体实现在infrastructure层的output适配器)获取数据,并将数据返回给input适配器。

package byronzhang.sample.hexagonalarchitecture.domain.service;

import byronzhang.sample.hexagonalarchitecture.application.ports.input.CreateProductUseCase;
import byronzhang.sample.hexagonalarchitecture.application.ports.input.GetProductUseCase;
import byronzhang.sample.hexagonalarchitecture.application.ports.output.ProductEventPublisher;
import byronzhang.sample.hexagonalarchitecture.application.ports.output.ProductOutputPort;
import byronzhang.sample.hexagonalarchitecture.domain.exception.ProductNotFound;
import byronzhang.sample.hexagonalarchitecture.domain.model.Product;
import byronzhang.sample.hexagonalarchitecture.domain.event.ProductCreatedEvent;
import lombok.AllArgsConstructor;

@AllArgsConstructor
public class ProductService implements CreateProductUseCase, GetProductUseCase {

    private final ProductOutputPort productOutputPort;

    private final ProductEventPublisher productEventPublisher;

    @Override
    public Product createProduct(Product product) {
        product = productOutputPort.saveProduct(product);
        productEventPublisher.publishProductCreatedEvent(new ProductCreatedEvent(product.getId()));
        return product;
    }

    @Override
    public Product getProductById(Long id) {
        return productOutputPort.getProductById(id).orElseThrow(() -> new ProductNotFound("Product not found with id " + id));
    }

}

同时,Domain层也可以抛出领域错误。领域错误将在infrastructure层被捕获并被处理(CustomizedExceptionAdapter)。

结论

在这篇文章中,我们通过一个简单的代码实例演示了如何借助六边形架构思想将业务逻辑拆分成三层:domain层、application层和infrastructure层。其实,代码层次的命名并不是关键,我们可能在不同的代码仓库中看到对这三层有不同的命名。记住六边形架构思想的核心是什么——将不变的业务逻辑和易变的外部依赖分开,使代码更易于开发、测试和维护。

注:本文的代码可从Github仓库获取Github仓库

0
Go语言学习之路——Go语言简… 十个问题弄清JVM&…

没有评论

No comments yet

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注