SpringBoot中使用Docker、Zipkin构建模块化

这篇博文深入探讨了如何构建Spring Boot应用程序、利用Docker一致的本地环境、Zipkin进行跟踪以及实现 100% 代码覆盖率的策略。

我们将探讨设置基于功能的模块化bookstore应用程序作为示例。我们将利用JPA数据持久性、SwaggerAPI 文档、Postgres数据库、Jacoco代码覆盖率以及Spring Modulith来记录应用程序结构。

先决条件:

  1. 您的系统上安装了 Java 21。您可以使用sdkman安装,并选择 Java 21 https://sdkman.io/usage
  2. Docker并Docker Compose安装用于设置本地环境。

克隆https://github.com/dmakariev/examples存储库

应用程序的结构
在构建复杂系统时,结构良好的方法对于管理可扩展性和可维护性至关重要。我们的bookstore应用程序分为几个不同的模块,每个模块都经过精心设计,用于处理业务的特定方面。这种分段有利于独立开发并简化维护,从而增强整体系统的稳健性。

高层结构
bookstore应用程序包括:

  • 库存模块Inventory :该模块的任务是管理库存水平以及与书籍库存的交互,确保系统地处理库存变化的实时更新。它是跟踪书店内库存情况的支柱。
  • 通知模块Notification :设计用于处理事件处理,该模块响应StockAddedEvent和StockRemovedEvent等事件。它向系统发出警报并通知相关利益相关者,从而促进跨应用程序的有效沟通。
  • 订单模块Order :该模块管理订单处理的所有方面,从最初的下单到最终的履行。它与库存模块无缝集成,确保库存水平实时准确调整,保持订单需求和库存供应之间的平衡。
  • 产品模块Product :负责维护产品的全面记录,包括书籍和作者的详细信息。该模块向其他模块提供关键数据,确保整个平台的一致性和准确性。
  • 用户模块User :该模块专注于所有用户与系统的交互,管理从身份验证到配置文件管理的任务。它保护用户信息,同时确保无缝、高效的用户体验。

这种结构化的模块方法不仅简化了开发和调试,还增强了应用程序对不断变化的业务需求和技术进步的适应性。每个模块都能独立运行,但又能与其他模块有效通信,从而确保应用程序架构的内聚性和稳健性。

最佳实践是遵循DDD 不同模块代表不同界限上下文 

应用程序的文件夹结构
应用程序采用结构化的层次结构,以便于明确划分关注点和提高可维护性:

├── Dockerfile
├── compose.yaml
├── lombok.config
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
    ├── main
    │   ├── asciidoc
    │   │   └── index.adoc
    │   ├── java
    │   │   └── com
    │   │       └── makariev
    │   │           └── examples
    │   │               └── spring
    │   │                   └── bookstore
    │   │                       ├── BookstoreApplication.java
    │   │                       ├── config
    │   │                       │   ├── GlobalRestControllerAdvice.java
    │   │                       │   └── SpringdocConfig.java
    │   │                       ├── inventory
    │   │                       │   ├── Inventory.java
    │   │                       │   ├── InventoryController.java
    │   │                       │   ├── InventoryRepository.java
    │   │                       │   ├── InventoryService.java
    │   │                       │   ├── StockAddedEvent.java
    │   │                       │   └── StockRemovedEvent.java
    │   │                       ├── notification
    │   │                       │   └── NotificationService.java
    │   │                       ├── order
    │   │                       │   ├── Order.java
    │   │                       │   ├── OrderController.java
    │   │                       │   ├── OrderItem.java
    │   │                       │   ├── OrderRepository.java
    │   │                       │   └── OrderService.java
    │   │                       ├── product
    │   │                       │   ├── Author.java
    │   │                       │   ├── AuthorController.java
    │   │                       │   ├── AuthorRepository.java
    │   │                       │   ├── AuthorService.java
    │   │                       │   ├── Book.java
    │   │                       │   ├── BookController.java
    │   │                       │   ├── BookRepository.java
    │   │                       │   ├── BookService.java
    │   │                       │   └── BookSummary.java
    │   │                       └── user
    │   │                           ├── Customer.java
    │   │                           ├── CustomerController.java
    │   │                           ├── User.java
    │   │                           ├── UserController.java
    │   │                           ├── UserRepository.java
    │   │                           └── UserService.java
    │   └── resources
    │       ├── application.properties
    │       ├── data.sql
    │       ├── schema.sql
    │       └── static
    │           └── index.html
    └── test
        ├── java
        │   └── com
        │       └── makariev
        │           └── examples
        │               └── spring
        │                   └── bookstore
        │                       ├── BookstoreApplicationTests.java
        │                       ├── ModularityTests.java
        │                       ├── inventory
        │                       │   ├── InventoryControllerIT.java
        │                       │   ├── InventoryControllerTest.java
        │                       │   ├── InventoryRepositoryTest.java
        │                       │   └── InventoryServiceTest.java
        │                       ├── order
        │                       │   ├── OrderControllerIT.java
        │                       │   ├── OrderControllerTest.java
        │                       │   ├── OrderRepositoryTest.java
        │                       │   └── OrderServiceTest.java
        │                       ├── product
        │                       │   ├── AuthorControllerIT.java
        │                       │   ├── AuthorControllerTest.java
        │                       │   ├── AuthorRepositoryTest.java
        │                       │   ├── AuthorServiceTest.java
        │                       │   ├── BookControllerIT.java
        │                       │   ├── BookControllerTest.java
        │                       │   ├── BookRepositoryTest.java
        │                       │   └── BookServiceTest.java
        │                       └── user
        │                           ├── CustomerControllerIT.java
        │                           ├── CustomerControllerTest.java
        │                           ├── UserControllerIT.java
        │                           ├── UserControllerTest.java
        │                           ├── UserRepositoryTest.java
        │                           └── UserServiceTest.java
        └── resources
            ├── application-integration-test.properties
            └── application-test.properties


关键文件夹和文件说明

  • /src/main/java/:包含应用程序的所有 Java 源文件,按模块(库存、通知、订单、产品、用户)分类。每个模块包括各自的控制器、服务、存储库和实体。
  • /src/main/resources/:包含配置文件(如 application.properties)、数据库初始化脚本(data.sql 和 schema.sql)以及静态资源(index.html)。
  • /src/test/:包含应用程序的所有测试用例,结构与主 Java 源代码目录类似。其中包括单元测试、集成测试和测试环境的配置文件。
  • Dockerfile 和 compose.yaml:定义用于构建应用程序镜像和使用 Docker Compose 设置多容器环境的 Docker 配置。
  • pom.xml:Maven 配置文件,用于管理依赖关系、插件以及构建应用程序所需的其他配置细节。
  • lombok.config:Lombok 库的配置文件,该库可帮助减少 Java 应用程序中的模板代码。

这种文件夹结构支持简洁有序的开发环境,便于导航和维护应用程序代码库。每个组件都按逻辑放置,以提高可理解性和可管理性,促进软件开发的最佳实践。

构建应用程序
构建 Spring Boot 应用程序涉及几个关键步骤和工具,旨在简化开发和测试流程。应用程序的核心是利用 Spring Boot Maven 插件,它简化了应用程序的打包和运行。对于集成测试,我们使用 Maven Failsafe 插件,确保在构建生命周期的集成测试阶段进行集成测试,而不会影响 Surefire 插件执行的早期单元测试。

标准构建命令
为了有效管理构建生命周期,我们使用了几个针对不同开发阶段定制的 Maven 命令:

单元测试:执行所有单元测试,同时跳过集成测试:
$ ./mvnw clean test

打包:创建一个可执行的 jar 文件,而不运行集成测试:
$ ./mvnw clean package

集成测试:包括集成测试的彻底验证:
$ ./mvnw verify

完整构建:执行包含文档和代码覆盖率分析的完整构建:
$ ./mvnw clean install -Pdocs,coverage


运行应用程序
出于开发目的,应用程序可以直接使用 Spring Boot 的嵌入式服务器运行:
$ ./mvnw spring-boot:run

或者,构建后,可以执行打包的应用程序:
$ java -jar ./target/bookstore-0.0.1-SNAPSHOT.jar

您还可以为不同的数据库指定运行时配置:

  • Postgres,它需要 Postgres 的 localhost 实例
    $ java -jar \ -Dspring.datasource.url=jdbc:postgresql://localhost:5432/example \ -Dspring.datasource.username=postgres \ -Dspring.datasource.password=postgres \ -Dspring.jpa.hibernate.ddl-auto=update \ ./target/bookstore-0.0.1-SNAPSHOT.jar
  • 内存中的 H2 数据库
    $ java -jar \ -Dspring.datasource.url=jdbc:h2:mem:example \ ./target/bookstore-0.0.1-SNAPSHOT.jar
  • H2 数据库文件系统 - 数据库数据存储在文件中
    $ java -jar \ -Dspring.datasource.url=jdbc:h2:file:./example-db-data \ -Dspring.jpa.hibernate.ddl-auto=update \ ./target/bookstore-0.0.1-SNAPSHOT.jar

其他 Maven 配置文件

  • docs简介

docs配置文件利用asciidoctor-maven-plugin.asciiDoc 文件生成全面的 HTML 文档src/main/asciidoc。该文档包括详细的模块描述、交互以及自动生成的 PlantUML 图以说明应用程序结构。
输出:文档被编译为 HTML 并存储在 中./target/generated-docs/index.html,提供应用程序架构的可访问且详细的概述。
  • coverage简介

该coverage配置文件在 的帮助下jacoco-maven-plugin,生成有关代码覆盖率的详细报告,确保跨单元和集成测试的广泛测试覆盖率。
输出:覆盖率报告放置在 中./target/site/jacoco/index.html,提供一个交互式界面来审查代码覆盖率指标并识别未测试的区域。

配置文件执行的示例命令

$ ./mvnw clean install -Pdocs
$ ./mvnw clean install -Pcoverage
$ ./mvnw clean install -Pdocs,coverage

这些命令确保我们的开发过程不仅高效而且彻底,提供所有必要的工具和报告以维持高标准的质量和文档。通过集成这些实践,我们增强了 Spring Boot 应用程序的健壮性和可读性,使其更易于管理、扩展和理解。

将 Docker Compose 集成到 Spring Boot 应用程序中
我们的 Spring Boot 应用程序利用 Docker Compose 来编排多个服务,确保它们部署在一致且可靠的环境中。 Docker Compose的使用方便了服务依赖关系的管理,并简化了我们本地开发环境中运行的服务的配置。下面简要概述了 Docker Compose 的配置方式及其管理的服务:

1、Docker Compose 配置
docker-compose.yaml文件定义了多个服务,包括后端应用程序、PostgreSQL 数据库、用于数据库管理的 pgAdmin 以及用于分布式跟踪的 Zipkin。以下是这些服务的编排方式:

  • 后端服务:配置为从 Dockerfile 构建,该服务在端口 8088 上运行书店后端,该端口映射到主机上的端口 8080。它使用环境变量中指定的凭据和配置连接到 PostgreSQL。数据库 (db):使用官方 PostgreSQL 映像并将数据存储在命名卷中,以便在容器重新启动时保留数据。
  • pgAdmin:提供基于 Web 的数据库管理界面,可通过端口 5050 访问。
  • Zipkin:提供跟踪功能来监视和排除分布式系统中的请求,可通过端口 9411 访问。

2、部署后访问服务
一旦docker compose up --build执行,它就会启动所有配置的服务。以下是可以在本地访问这些服务的 URL:


此 Docker Compose 设置不仅确保应用程序的每个组件都正确配置和互连,而且还提供了一个强大的平台,用于在模拟生产环境中开发、测试和监控应用程序的性能。

结论
在这篇博文中,我们探讨了如何详细设置和配置基于功能的 Spring Boot 应用程序,以满足现代应用程序和微服务的复杂要求。

  • 我们的方法强调简洁的代码和简洁的架构,促进了组件之间的低耦合和高内聚
  • 通过使用 Docker Compose,我们简化了 PostgreSQL、pgAdmin 和 Zipkin 等基本服务的部署,增强了我们的开发和可观察性环境。
  • 详细的文档和高代码覆盖率不仅是我们的理想目标,也是我们勤奋使用 Maven 配置文件所取得的实际成果。

这种系统化的方法不仅提高了开发效率,还为开发人员提供了有效监控和管理应用程序的强大工具。

这些实践体现了构建可扩展、可维护和高质量软件的必要标准,确保每个组件既能独立又能作为整个系统的一部分高效运行。