阿里P7架構師:創建自己的定製的Spring Boot Starter快速指南

阿里P7架構師:創建自己的定製的Spring Boot Starter快速指南

 

通過一個例子來了解如何實現一個Spring Boot Starter。對於我們正在構建的每個Spring Boot應用程序,我們不希望從頭開始實現某些跨領域的問題。相反,我們希望一次性實現這些功能,並根據需要將它們作爲組件包含在任何應用程序中。

在Spring Boot中,用於提供此類交叉問題的模塊的術語是“starter”。Spring Boot starter的一些示例用例是:

  • 提供可配置和/或默認的日誌記錄配置,或使其易於登錄到中央日誌服務器
  • 提供可配置和/或默認的安全配置
  • 提供可配置和/或默認的錯誤處理策略
  • 爲中央消息傳遞基礎設施提供適配器
  • 集成第三方庫並使其可配置爲與Spring Boot一起使用
  • ...

在本文中,我們將構建一個Spring Boot啓動器,它允許Spring Boot應用程序通過虛構的中央消息傳遞基礎架構輕鬆發送和接收事件。

在我們深入瞭解創建Spring Boot Starter的細節之前,讓我們討論一些有助於理解Starter工作的關鍵字。

阿里P7架構師:創建自己的定製的Spring Boot Starter快速指南

 

什麼是應用程序上下文?

在Spring應用程序中,應用程序上下文是組成應用程序的對象(或“bean”)的網絡。它包含我們的Web控制器,服務,存儲庫以及我們的應用程序可能需要的任何(通常是無狀態的)對象。

什麼是配置?

使用註釋@Configuration標註的類,扮演添加到應用程序上下文的bean工廠。它可能包含帶註釋的工廠方法,@Bean其返回值由Spring自動添加到應用程序上下文中。

簡而言之,Spring配置爲應用程序上下文提供bean。

什麼是自動配置?

自動配置是Spring自動發現的@Configuration類。只要該類位於在類路徑classpath上,即可自動配置,並將配置的結果添加到應用程序上下文中。自動配置可以是有條件的,使得其激活取決於外部因素,例如具有特定值的特定配置參數。

什麼是自動配置模塊?

自動配置模塊是包含自動配置類的Maven或Gradle模塊。這樣,我們就可以構建自動爲應用程序上下文做貢獻的模塊,添加某個功能或提供對某個外部庫的訪問。我們在Spring Boot應用程序中使用它所要做的就是在我們的pom.xml或者包含它的依賴項build.gradle。

Spring Boot團隊大量使用此方法將Spring Boot與外部庫集成。

什麼是Spring Boot Starter?

最後,Spring Boot Starter是一個Maven或Gradle模塊,其唯一目的是提供“使用某個功能”“開始”所需的所有依賴項。這通常意味着它是一個單獨的pom.xml或build.gradle文件,包含一個或多個自動配置模塊的依賴項以及可能需要的任何其他依賴項。

在Spring Boot應用程序中,我們只需要包含此啓動器Starter即可使用該功能。

阿里P7架構師:創建自己的定製的Spring Boot Starter快速指南

圖不重要

案例

通過一個例子來了解如何實現一個Spring Boot Starter,想象一下,我們正在微服務環境中工作,並希望實現一個允許服務異步通信的啓動器。我們正在建造的Starter將提供以下功能:

  • EventPublisher事件發佈:允許我們將事件發送到中央消息傳遞基礎結構的bean
  • 一個抽象EventListener事件監聽類,可以實現從中央消息傳遞基礎結構訂閱某些事件。

請注意,本文中的實現實際上不會連接到中央消息傳遞基礎結構,而是提供虛擬實現。本文的目標是展示如何構建Spring Boot Starter,而不是如何進行消息傳遞。

設置Gradle構建

由於啓動器Starter是跨多個Spring Boot應用程序的交叉問題,它應該存在於自己的代碼庫中並擁有自己的Maven或Gradle模塊。我們將使用Gradle作爲選擇的構建工具,但它與Maven非常相似。

我們需要聲明的依賴基本Spring Boot啓動我們的build.gradle文件:

plugins {
 id 'io.spring.dependency-management' version '1.0.8.RELEASE'
 id 'java'
}
dependencyManagement {
 imports {
 mavenBom("org.springframework.boot:spring-boot-dependencies:2.1.7.RELEASE")
 }
}
dependencies {
 implementation 'org.springframework.boot:spring-boot-starter'
 testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

要獲得與某個Spring Boot版本兼容的基本啓動程序版本,我們使用Spring Dependency Management插件來包含該特定版本的BOM(物料清單)。

這樣,Gradle在此BOM中查找啓動程序的兼容版本(以及Spring Boot需要的任何其他依賴項的版本),我們不必手動聲明它。

阿里P7架構師:創建自己的定製的Spring Boot Starter快速指南

這個圖也不重要

提供自動配置

提供了一個@Configuration類實現事件發佈者:

@Configuration
class EventAutoConfiguration {
 @Bean
 EventPublisher eventPublisher(List<EventListener> listeners){
 return new EventPublisher(listeners);
 }
}

此配置包括的@Bean是我們提供給Starter所需的所有定義。這裏是需將EventPublisherbean 添加到應用程序上下文中。

EventPublisher需要知道所有的虛擬實現,EventListeners因此它可以將事件傳遞給它們,因此我們讓Spring注入EventListeners應用程序上下文中所有可用的列表。

要使我們的配置成爲自動配置,我們將其列在文件中META-INF/spring.factories:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
 io.reflectoring.starter.EventAutoConfiguration

Spring Boot會搜索spring.factories它在類路徑中找到的所有文件,並加載在其中聲明的配置。

有了這個EventAutoConfiguration類,我們現在可以爲Spring Boot starter自動激活單點入口。

使其成爲可選

允許是否可以禁用Spring Boot starter總是一個好主意。在提供對諸如消息傳遞服務之類的外部系統的訪問時,這尤其重要。例如,該服務在測試環境中不可用,因此我們希望在測試期間關閉該功能。

我們可以使用Spring Boot的條件註釋使我們的入口點配置成爲可選:

@Configuration
@ConditionalOnProperty(value = "eventstarter.enabled", havingValue = "true")
@ConditionalOnClass(name = "io.reflectoring.KafkaConnector")
class EventAutoConfiguration {
 ...
}

通過使用ConditionalOnProperty,我們告訴Spring只在屬性eventstarter.enabled設置爲true的情況下將(以及它聲明的所有bean)包含到應用程序上下文中。

@ConditionalOnClass註解告訴Spring:只有在io.reflectoring.KafkaConnector出現類路徑classpath時,才能激活自動配置(這僅僅是一個虛擬類向人們展示了使用條件註釋)。

阿里P7架構師:創建自己的定製的Spring Boot Starter快速指南

認認真真講技術!

使其可配置

對於在多個應用程序中使用的庫,例如我們的啓動程序,將行爲設置爲儘可能可行是一個好主意。

想象一下,應用程序只對某些事件感興趣。爲了使每個應用程序可配置,我們可以在application.yml(或application.properties)文件中提供已啓用事件的列表:

eventstarter:
 listener:
 enabled-events:
 - foo
 - bar

爲了在我們的入門代碼中輕鬆訪問這些屬性,我們可以提供一個@ConfigurationProperties類:

@ConfigurationProperties(prefix = "eventstarter.listener")
@Data
class EventListenerProperties {
 /**
 * List of event types that will be passed to {@link EventListener}
 * implementations. All other events will be ignored.
 */
 private List<String> enabledEvents = Collections.emptyList();
}

通過使用@EnableConfigurationProperties註釋我們的入口點配置來啓用EventListenerProperties類:

@Configuration
@EnableConfigurationProperties(EventListenerProperties.class)
class EventAutoConfiguration {
 ...
}

最後,我們可以讓Spring將EventListenerPropertiesbean 注入我們需要的任何地方,例如在我們的抽象EventListener類中過濾掉我們不感興趣的事件:

@RequiredArgsConstructor
public abstract class EventListener {
 private final EventListenerProperties properties;
 public void receive(Event event) {
 if(isEnabled(event) && isSubscribed(event)){
 onEvent(event);
 }
 }
 private Boolean isSubscribed(Event event) {
 return event.getType().equals(getSubscribedEventType());
 }
 private Boolean isEnabled(Event event) {
 return properties.getEnabledEvents().contains(event.getType());
 }
}

創建IDE友好的配置元數據

使用eventstarter.enabled和eventstarter.listener.enabled-events我們爲啓動器指定了兩個配置參數。如果這些參數讓開發人員在配置文件中輸入時自動完成,那將是很好的。

Spring Boot提供了一個註釋處理器,可以從找到的所有@ConfigurationProperties類中收集有關配置參數的元數據。我們只是將它包含在我們的build.gradle文件中:

dependencies {
 ...
 annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
}

此註解處理器將生成META-INF/spring-configuration-metadata.json包含有關我們EventListenerProperties類中的配置參數的元數據的文件。此元數據包含字段上的Javadoc,因此請務必使Javadoc儘可能清晰。

在IntelliJ中,Spring Assistant插件將讀取此元數據併爲這些屬性提供自動完成功能。

現在還留下eventstarter.enabled問題,它沒有在@ConfigurationProperties的列表中。

我們可以通過創建文件META-INF/additional-spring-configuration-metadata.json,手動添加此屬性:

{

 "properties": [
 {
 "name": "eventstarter.enabled",
 "type": "java.lang.Boolean",
 "description": "Enables or disables the EventStarter completely."
 }
 ]
}

然後,註釋處理器將自動將此文件的內容與自動生成的文件合併,以供IDE工具選取。該文件的格式記錄在參考手冊中。

改善啓動時間

對於類路徑上的每個自動配置類,Spring Boot必須評估@Conditional...註釋中編碼的條件,以決定是否加載自動配置及其所需的所有類。根據Spring Boot應用程序中啓動器的大小和數量,這可能是非常昂貴的操作並影響啓動時間。

還有另一個註釋處理器可生成有關所有自動配置條件的元數據。Spring Boot在啓動期間讀取此元數據,並且可以過濾掉不滿足條件的配置,而無需實際檢查這些類。

要生成此元數據,我們只需將註釋處理器添加到啓動器模塊:

dependencies {
 ...
 annotationProcessor 'org.springframework.boot:spring-boot-autoconfigure-processor'
}

在構建期間,元數據將生成到META-INF/spring-autoconfigure-metadata.properties文件中,如下所示:

io.reflectoring.starter.EventAutoConfiguration=
io.reflectoring.starter.EventAutoConfiguration.ConditionalOnClass=io.reflectoring.KafkaConnector
io.reflectoring.starter.EventAutoConfiguration.Configuration=

我不確定爲什麼元數據包含@ConditionalOnClass條件但不包含@ConditionalOnProperty條件。如果您知道原因,請在評論中告訴我。

阿里P7架構師:創建自己的定製的Spring Boot Starter快速指南

 

使用入門

現在啓動器已經完成,它已準備好,可以包含在Spring Boot應用程序中了。

在build.gradle文件中添加單個依賴項即可實現包含它:

dependencies {
 ...
 implementation project(':event-starter')
}

在上面的示例中,starter是同一Gradle構建中的模塊,因此我們不必像在完全限定的Maven中需要使用來定位標識starter。

我們現在可以使用上面介紹的配置參數配置啓動器。希望我們的IDE能夠評估我們創建的配置元數據,併爲我們自動完成參數名稱。

要使用我們的事件啓動器,我們現在可以EventPublisher在bean中注入並使用它來發布事件。此外,我們可以創建擴展EventListener類的bean 來接收和處理事件。

歡迎工作一到五年的Java工程師朋友們加入JavaQQ羣:219571750,羣內提供免費的Java架構學習資料(裏面有高可用、高併發、高性能及分佈式、Jvm性能調優、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章