Spring Modulith 1.3 的新特性是什麼?

工程 | Oliver Drotbohm | 2024 年 11 月 22 日 | ...

經過半年的開發,Spring Modulith 1.3 GA 已釋出。它包含了大量新功能、改進,以及最重要的是社群貢獻。讓我帶你瞭解其中一些最有趣的內容。

基線升級

像往常一樣,Spring Modulith 的新次要版本升級到了 Spring Boot 和 Spring Framework 的最新版本,分別為 3.46.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 註解使其也成為一個巢狀應用程式模組。在這種安排下,適用以下訪問規則:

  • Nested 中的程式碼只能從 Inventory 或巢狀在 Inventory 內的同級應用程式模組暴露的任何型別中訪問。
  • Nested 模組中的任何程式碼都可以訪問父模組中的程式碼,甚至是內部程式碼。也就是說,NestedApiNestedInternal 都可以訪問 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(…) 變體轉換為 ApplicationModuleSources。

整合測試

最佳化整合測試的執行一直是 Spring Modulith 的核心功能。可以使用 @ApplicationModuleTest 註解單獨或以不同程度的協作方式引導應用程式模組。

在 1.3 版本中,我們透過 JUnit Jupiter 擴充套件擴充套件了該支援,該擴充套件將分析對應用程式所做的更改,並且在測試執行時僅選擇確實需要執行的整合測試來執行。預設情況下,我們會考慮未提交的更改以及當前分支跟蹤分支之上的提交。為了最佳化 CI 系統上的測試執行,可以為該擴充套件提供一個提交雜湊(通常是最新成功構建提交的雜湊),作為計算需要考慮的更改檔案的參考。

Some console output showing tests being skipped that would test functionality not affected by the current changes made to the repository

如您所見,未受專案更改影響的測試會被跳過。非常感謝貢獻此功能的Lukas DohmenDavid 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,便於預覽。每當您使用 DocumenterwriteDocumentation(…) 變體之一時,就會生成該文件。或者,在您選擇性地觸發了單個圖表和應用程式模組 Canvas 的生成之後,顯式呼叫 writeAggregatingDocument(…)

Canvas 方便地佈局了構成應用程式模組表面的所有程式碼片段。我們一直透過整合第三方庫和相當複雜的構建設定,為 Canvas 提供了包含型別和方法(針對事件監聽器)上存在的 Javadoc 的選項。在 1.3 版本中,我們現在提供了一個註解處理器(位於 spring-modulith-apt 中),它可以自動將您的程式碼庫的 Javadoc 提取到可重用的 JSON 文件中,並且 Canvas 生成已更新為如果存在該文件則透明地使用它。現在 spring-modulith-starter-core 會自動包含它。

第三方整合

最後,為了方便起見,如果 classpath 中存在 jMolecules,我們現在會自動觸發其提供的基於 ArchUnit 的架構驗證,例如針對六邊形、洋蔥或分層架構的驗證。

訂閱 Spring 新聞通訊

透過 Spring 新聞通訊保持聯絡

訂閱

領先一步

VMware 提供培訓和認證,助您飛速提升。

瞭解更多

獲得支援

Tanzu Spring 透過一項簡單的訂閱提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案。

瞭解更多

即將舉行的活動

檢視 Spring 社群所有即將舉行的活動。

檢視全部