Spring Modulith:快速开始

B站影视 韩国电影 2025-09-10 20:37 3

摘要:提供接口 (Provided Interface): 这是一个模块暴露给其他模块的 API。它通常通过模块内部由 Spring Bean 实例实现的服务(例如,服务接口或门面类)以及该模块发布的应用程序事件来体现。这些是其他模块可以合法调用的入口点。内部实现组

在本节中,创建一个简单的 Spring Boot 项目,构建我们的第一个模块化应用程序。

在 Spring Boot 应用程序中,一个应用程序模块是一个功能单元,它由以下几个关键部分组成:

提供接口 (Provided Interface) : 这是一个模块暴露给其他模块的 API。它通常通过模块内部由 Spring Bean 实例实现的服务(例如,服务接口或门面类)以及该模块发布的应用程序事件来体现。这些是其他模块可以合法调用的入口点。内部实现组件 (Internal Implementation Components) : 这些是构成模块内部逻辑的私有实现细节。这些组件 不应被其他模块直接访问 ,它们是模块封装性(即信息隐藏)的基石。所需接口 (Required Interface) : 这是一个模块对其他模块所暴露 API 的引用。这种引用通常以 Spring Bean 依赖注入(即注入其他模块的服务)、监听其他模块发布的应用程序事件,以及读取其他模块暴露的配置属性的形式存在。

Spring Modulith 提供了在 Spring Boot 应用程序 #技术分享中表达和管理这些模块的不同方式,这些方式主要区别在于整体布局(arrangement)所涉及的复杂程度和所能提供的约束强度。

首先,使用 Spring Initializr ( start.spring.io/ ) 创建一个包含 Spring Web 依赖的 Maven 项目。然后,打开项目的 pom.xml 文件,确保它包含了 Spring Boot 的基础依赖,并添加 Spring Modulith 的核心依赖。

171.3.5

org.springframework.bootspring-boot-starter-weborg.springframework.modulithspring-modulith-starter-coreorg.projectlomboklomboktrueorg.springframework.bootspring-boot-starter-testtestorg.springframework.modulithspring-modulith-starter-testtestorg.springframework.modulithspring-modulith-bom${spring-modulith.version}pomimportsrc/main/java/org/niujiao/spring_modulith_tutorials/├── SpringModulithTutorialsApplication.java├── notification/

NiujiaoNotificationService.java

@Service @Slf4j public class NiujiaoNotificationService { public void send(Notification notification) { String message = String.format("Notification for type '%s' with content: '%s'", notification.getType, notification.getContent); log.info("Notification Module (Internal): Sending notification internally: {}", message); } }

Notification.java

@Data @AllArgsConstructor public class Notification { private String type; private String content; }

NotificationFacadeService

@Slf4j @Service @RequiredArgsConstructor public class NotificationFacadeService { protected final NiujiaoNotificationService niujiaoNotificationService; public void send(Notification notification) { log.info("Notification Module (Facade): Received notification: {} -niujiaoNotificationService.send(notification); log.info("Notification Module (Facade): Notification sent successfully!"); } }

Order

@NoArgsConstructor @AllArgsConstructor @Data public class Order { private String no; private List items; @NoArgsConstructor @AllArgsConstructor @Data public static class Item { private String productId; private Integer quantity; private Integer price; } }

OrderService

@RequiredArgsConstructor @Service @Slf4j public class OrderService { private final NotificationFacadeService notificationFacadeService; public void createOrder(Order order) { log.info("Order Module: Attempting to create order."); order.setNo(System.currentTimeMillis +log.info("Order Module: Order created successfully, order number: {}", order.getNo); Notification notification = new Notification("order_create", "Order created, order no is " +notificationFacadeService.send(notification); log.info("Order Module: Notification sent for order creation."); } }

SpringModulithTutorialsApplication.java

@SpringBootApplication public class SpringModulithTutorialsApplication { public static void main(String args) { SpringApplication.run(SpringModulithTutorialsApplication.class, args); } @Bean CommandLineRunner run(OrderService orderService) { return args -> { System.out.println("\n---Order.Item item = new Order.Item("apple", 1, 500); Order order = new Order; order.setItems(List.of(item)); orderService.createOrder(order); System.out.println("---}; } }

运行 SpringModulithTutorialsApplication 主类,您应该会在控制台日志中看到类似以下的输出:

--- 启动 Spring Modulith 示例 ---2025-05-10T12:20:14.985+08:00 INFO 26112 --- [spring-modulith-tutorials] [ main] o.n.s.order.OrderService : Order Module: Attempting to create order.2025-05-10T12:20:14.986+08:00 INFO 26112 --- [spring-modulith-tutorials] [ main] o.n.s.order.OrderService : Order Module: Order created successfully, order number: 17468508149852025-05-10T12:20:14.987+08:00 INFO 26112 --- [spring-modulith-tutorials] [ main] o.n.s.n.NotificationFacadeService : Notification Module (Facade): Received notification: order_create - Order created, order no is 1746850814985. Items: [Order.Item(productId=apple, quantity=1, price=500)]2025-05-10T12:20:14.988+08:00 INFO 26112 --- [spring-modulith-tutorials] [ main] o.n.s.n.i.NiujiaoNotificationService : Notification Module (Internal): Sending notification internally: Notification for type 2025-05-10T12:20:14.988+08:00 INFO 26112 --- [spring-modulith-tutorials] [ main] o.n.s.n.NotificationFacadeService : Notification Module (Facade): Notification sent successfully!2025-05-10T12:20:14.988+08:00 INFO 26112 ------ 示例执行完毕 ---

Spring Modulith 能够检查我们的代码库,并根据模块化约束验证模块间的依赖是否合法。

通过编写一个简单的 Spring Boot 测试来执行模块验证,代码如下:

@SpringBootTest class SpringModulithTutorialsApplicationTests { @Test void verifyApplicationModuleModel { System.out.println("\n---ApplicationModules modules = ApplicationModules.of(SpringModulithTutorialsApplication.class); System.out.println("---modules.forEach(System.out::println); System.out.println(""); modules.verify; System.out.println("---System.out.println("---} }

运行这个测试方法 verifyApplicationModuleModel 方法,在测试的控制台输出中看到类似以下的信息:

--- 验证 Spring Modulith 模块结构 ------ 检测到的模块信息 --- # Notification> Logical name: notification> Base package: org.niujiao.spring_modulith_tutorials.notification> Excluded packages: none> Spring beans:> +o ….internal.NiujiaoNotificationService# Order> Logical name: order> Base package: org.niujiao.spring_modulith_tutorials.order> Excluded packages: none> Spring beans:> + ….OrderService 验证 Spring Modulith 模块结构完毕 ---

Spring Modulith 默认将 Spring Boot 应用程序主包(即包含 @SpringBootApplication 主类的包)下的每个直接子包识别为独立的 应用程序模块 。模块的封装性取决于其内部结构:

对于 没有子包简单模块 ,其内部代码主要通过 Java 的 包作用域 隐藏,仅包中声明为 public 的类型构成对外 API;对于 包含子包的模块 (例如我们示例中的 notification.internal 子包),Spring Modulith 会将这些子包内的所有类型视为模块的 内部实现细节 ,无论其 Java 访问修饰符为何,默认阻止其他模块直接访问或注入,从而严格强制模块边界,确保架构的清晰与健。

modules.verify 验证包括以下规则:

应用模块级别无循环依赖 —— 模块之间的依赖关系必须形成一个有向无环图。仅通过 API 包进行外部模块访问 —— 所有引用位于应用模块内部包中的类型的引用都将被拒绝。详细信息请参阅高级应用模块。允许对开放应用模块的内部进行依赖。仅显式允许的应用模块依赖(可选) —— 应用模块可以选择通过 @ApplicationModule(allowedDependencies = …) 定义允许的依赖关系。

将 OrderService 直接依赖并调用 NiujiaoNotificationService ,而非通过其公共门面 NotificationFacadeService

@RequiredArgsConstructor@Service@Slf4jpublic class OrderService {private final NiujiaoNotificationService niujiaoNotificationService;public void createOrder(Order order) { log.info("Order Module: Attempting to create order."); order.setNo(System.currentTimeMillis +log.info("Order Module: Order created successfully, order number: {}", order.getNo);Notification notification = new Notification("order_create", "Order created, order no is " + order.getNo + ". Items: " + order.getItems);niujiaoNotificationService.send(notification); log.info("Order Module: Notification sent for order creation."); } }

重新运行 SpringModulithTutorialsApplicationTests 中的 verifyApplicationModuleModel 测试方法。

@Testvoid writeDocumentationSnippets { ApplicationModules modules = ApplicationModules.of(SpringModulithTutorialsApplication.class); new Documenter(modules) .writeModulesAsPlantUml .writeIndividualModulesAsPlantUml;}

C4图将以 puml 文件的形式创建在 target\spring-modulith-docs 目录中,将模块结构以图形化的方式呈现,帮助我们快速理解项目的宏观架构。

--- 感谢您的阅读!希望这部分内容对您有所启发。如果您觉得有价值,请不吝点赞支持,并在评论区留下您的想法,一起交流学习!别忘了关注我,获取后续更精彩的教程内容。您的每一个肯定和互动,都是我持续分享知识的动力!

来源:墨码行者

相关推荐