领先一步
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
s。
优化集成测试的执行一直是 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 版本中移除我们的artifact。
我们的文档支持也带来了一些有趣的功能。首先,感谢 Cora Iberkleid,默认的文档生成过程会生成一个聚合文档,其中包含创建的所有单个artifact,便于预览。每当您使用 Documenter
的 writeDocumentation(…)
变体之一时,就会生成该文档。或者,在您选择性地触发了单个图表和应用程序模块 Canvas 的生成之后,显式调用 writeAggregatingDocument(…)
。
Canvas 方便地布局了构成应用程序模块表面的所有代码片段。我们一直通过集成第三方库和相当复杂的构建设置,为 Canvas 提供了包含类型和方法(针对事件监听器)上存在的 Javadoc 的选项。在 1.3 版本中,我们现在提供了一个注解处理器(位于 spring-modulith-apt
中),它可以自动将您的代码库的 Javadoc 提取到可重用的 JSON 文档中,并且 Canvas 生成已更新为如果存在该文档则透明地使用它。现在 spring-modulith-starter-core
会自动包含它。
最后,为了方便起见,如果 classpath 中存在 jMolecules,我们现在会自动触发其提供的基于 ArchUnit 的架构验证,例如针对六边形、洋葱或分层架构的验证。