领先一步
VMware 提供培训和认证,助您加速进步。
了解更多经过半年的开发,Spring Modulith 1.3 GA已经发布。它充满了新功能、改进,而且——最重要的是——社区贡献。让我带你了解其中一些最有趣的内容。
一如既往,Spring Modulith 的新次要版本会升级到最新的 Spring Boot 和 Spring Framework 版本,分别是3.4和6.2。即便如此,我们仍然兼容它们的前代版本,以便你可以选择性地升级到 Spring Modulith 1.3,而无需升级到最新的 Boot 和 Framework 版本。
Spring Modulith 的核心抽象在内部得到了显著的改版,以支持一些很棒的新功能。一个应用程序模块现在可以包含嵌套的模块,这些模块对其他同级模块是隐藏的。这为组织应用程序提供了另一个层级的手段。嵌套应用程序模块是通过在由定义的检测策略发现的模块的基础包内嵌套的包上使用 Spring Modulith 的 @ApplicationModule (或 jMolecules 的 @Module) 来声明的。
🍃 Example
└─ 🖿 src/main/java
|
├─ 📦 example
| └─ 🟢 Application.java
|
| -> Inventory
|
├─ 📦 example.inventory
| ├─ 🟢 InventoryManagement.java
| └─ 🔴 SomethingInventoryInternal.java
├─ 📦 example.inventory.internal
| └─ 🔴 SomethingInventoryInternal.java
|
| -> Inventory > Nested
|
├─ 📦 example.inventory.nested
| ├─ ☕ package-info.java // @ApplicationModule
| └─ 🟠 NestedApi.java
├─ 📦 example.inventory.nested.internal
| └─ 🔴 NestedInternal.java
|
| -> Order
|
└─ 📦 example.order
├─ 🟢 OrderManagement.java
└─ 🔴 SomethingOrderInternal.java
在这个例子中,inventory 是一个应用程序模块,如参考文档中所述。nested 包上的 @ApplicationModule 注解导致该包本身也成为一个嵌套的应用程序模块。在这种安排下,以下访问规则适用:
NestedApi 和 NestedInternal 都可以访问 inventory.internal.SomethingInventoryInternal。nested (或任何子包) 中的任何代码都可以访问 OrderManagement。
Spring Modulith 的默认应用程序模块检测策略假设所有应用程序模块都位于相同的包命名空间中。直到现在,向该安排中添加其他包只能通过提前知道要包含的包并在 @Modulithic(additionalPackages = "…" 中配置它们来实现。从 1.3 版本开始,我们引入了一个 SPI ApplicationModuleSourceFactory,可以通过 META-INF/spring.factories 注册,并用于声明要扫描的根包、显式的应用程序模块基础包,并可选地为声明的根包定制要使用的应用程序模块检测策略。
package example;
public class CustomApplicationModuleSourceFactory implements ApplicationModuleSourceFactory {
@Override
public List<String> getRootPackages() {
return List.of("com.acme.toscan");
}
@Override
public ApplicationModuleDetectionStrategy getApplicationModuleDetectionStrategy() {
return ApplicationModuleDetectionStrategy.explicitlyAnnotated();
}
@Override
public List<String> getModuleBasePackages() {
return List.of("com.acme.module");
}
}
上面的例子将使用 com.acme.toscan 来检测其中的显式声明的模块,并从 com.acme.module 创建一个应用程序模块。从这些返回的包名将通过 ApplicationModuleDetectionStrategy 中公开的相应 getApplicationModuleSource(…) 变体转换为 ApplicationModuleSource。
优化集成测试的执行一直是 Spring Modulith 的核心功能。应用程序模块可以使用 @ApplicationModuleTest 注解单独或以不同程度的协作方式启动。
在 1.3 版本中,我们通过 JUnit Jupiter 扩展扩展了此支持,该扩展将分析您应用程序所做的更改,并在测试运行时仅选择真正需要执行的集成测试。默认情况下,我们考虑未提交的更改和您当前分支的跟踪分支之上的提交。为了优化 CI 系统上的测试执行,可以为扩展提供一个提交哈希——通常是最近一次成功构建的提交的哈希——作为参考,以计算要考虑的更改文件。

正如您所见,未受项目更改影响的测试已被跳过。非常感谢 Lukas Dohmen 和 David Bilge 对此功能的贡献。
在集成测试支持方面,另一个微小但有用的新增功能是 @ApplicationModuleTest 现在可以通过其新引入的 module 属性显式定义要执行的模块。这使得集成测试可以位于应用程序模块的包空间之外,这也是由 Lukas 贡献的。
Spring Modulith 1.3 在其事件发布支持方面提供了大量新功能。首先,我们提供了两种新的完成模式,可以通过 spring.modulith.events.completion-mode 属性进行配置。第一个新的完成模式 (delete) 会立即删除已发布的事件,而不是设置完成日期。这意味着注册表中的条目数量会保持较小,因此对于发布大量事件的系统,性能开销会更小。
立即删除已完成的发布存在无法访问它们的缺点,例如用于统计目的。因此,我们还添加了一种归档 (archive) 模式,该模式维护一个专用的发布归档,已完成的发布将被移动到其中。这提供了相同的事件发布性能改进,但将已完成的发布单独保留。
直到现在,事件发布都是通过装饰事务性应用程序监听器来完成的。这意味着完成代码只能访问已消耗的原始应用程序事件和监听器的标识符,而不能访问单个发布的标识符。
在 Spring Modulith 1.3 中,事件发布注册表会跟踪当前正在进行的事件发布,从而允许我们发出引用发布标识符的发布完成。这允许各个后端实现显著提高完成操作的性能,因为索引可以使用得更有效。
事件发布注册表的 [关系数据库后端] 现在支持另外三个数据库,即 MariaDB、Oracle DB 和 Microsoft SQL Server。此外,可以为支持模式的数据库定义用于 DDL 执行和常规操作的模式。
最后,spring.modulith.republish-outstanding-events-on-restart 已被弃用,取而代之的是新引入的 spring.modulith.events.republish-outstanding-events-on-restart,以保持一致性。
Spring Modulith 轻松将应用程序事件外部化到其他系统的支持也带来了不少新功能。首先,发送的消息现在可以关联头部信息。为此,EventExternalizingConfiguration 现在公开了各种 headers(…) 方法,允许为一般事件或特定事件类型注册自定义提取器。
@Configuration
class MyConfiguration {
@Bean
EventExternalizingConfiguration config(SomeBean bean) {
return EventExternalizingConfiguration.defaults(…)
.headers(event -> Map.of("signature", bean.signMessage(event)))
.build();
}
}
为了动态计算外部化事件的路由目标,@Externalized 现在支持 SpEL 表达式来定义它们,除了之前已经支持的动态路由键。
我们的好朋友 Josh Long 贡献了一个新的外部化适配器,用于将事件写入 Spring 的 MessageChannel 抽象。该接口由 Spring Integration 的消息通道实现,因此您现在可以根据需要无缝地将应用程序事件输入到其中。
将事件外部化到 Amazon SQS 和 SNS 的支持已移至 Spring Cloud for AWS 的当前版本(感谢 Maciej Walkowiak)。因此,我们正式弃用我们自己的实现,转而支持他们的实现,这些实现是 Spring Modulith 原生实现的副本,应该是可以直接替换的。我们计划在明年发布的 2.0 版本中移除我们的工件。
我们的文档支持也带来了一些有趣的功能。首先,感谢 Cora Iberkleid,默认的文档生成过程会生成一个包含所有单独创建的工件的聚合文档,方便预览。每当您使用 Documenter 的 writeDocumentation(…) 变体之一时,就会生成该文档。或者,在您选择性地触发生成单个图和应用程序模块画布后,显式调用 writeAggregatingDocument(…)。
画布方便地布局了构成其表面的应用程序模块的所有代码片段。我们一直通过集成第三方库和相当复杂的构建设置,提供了此画布包含 Javadoc(针对类型和方法,用于事件监听器)的选项。在 1.3 版本中,我们现在提供了一个注解处理器(在 spring-modulith-apt 中),它可以自动将代码库的 Javadoc 提取到可重用的 JSON 文档中,并且 Canvas 生成已更新为在存在时透明地使用该文档。它现在由 spring-modulith-starter-core 自动包含。
最后,为了方便起见,我们现在会自动触发 [基于 ArchUnit] 的架构验证(如果存在于类路径上),例如 jMolecules 提供的关于 [Hexagonal、Onion 或分层架构] 的验证。