SpringBoot魔法堂:說說帶智慧提示的spring-boot-starter

^_^肥仔John發表於2020-11-11

前言

前幾個月和隔壁組的老王閒聊,他說專案的供應商離職率居高不下,最近還有開發剛接手ESB訂閱釋出介面才兩週就提出離職,而他能做的就只有苦笑和默默地接過這個爛攤子了。
而然幸福的家庭總是相似的,而不幸的我卻因業務變革走上了和老王一樣的道路。單單是介面的開發居然能迫使一位開發毅然決然地離職,我既不相信是人性的扭曲,更不信是道德的淪喪。
拋開這個富有色彩的故事而言,我發現原來的專案存在如下問題:

  1. 沒有使用任何現代依賴管理和構建工具(如Maven, Gradle),直接把所依賴的Jar包存放在專案目錄下的lib目錄中,日積月累導致lib目錄下存放大量無用Jar包;
  2. 沒有使用程式碼版本管理工具管理程式碼;
  3. 技術文件欠缺,全靠師傅帶徒弟的方式傳授框架使用方式和開發流程;
  4. 機械性配置項多,而後來的開發人員大多隻能依葫蘆畫瓢新增配置,既容易出錯同時又增加問題排查的難度。
    針對前兩個問題,我們只需梳理出必須的依賴項並加入Maven或Gradle管理,然後託管到Git即可。
    而後兩者則可以通過spring-boot-starter將必選依賴項和配置統一管理,並附上相關技術文件;然後通過模板模式和註解簡化開發流程,提供Demo降低入門難度。
    最後就可以把具體的業務功能開發交給供應商處理,我們專心做好過程管理和驗收即可。

本文將著重分享spring-boot-starter開發的事項,請坐好扶穩!

命名規範

在自定義starter前我們總要思考如何命名我們的starter,而官方提供如下的命名規範:

  1. 官方的starter以spring-boot-starter作為字首命名專案
    如:spring-boot-starter-web
  2. 非官方的則以spring-boot-starter作為字尾命名專案
    如:mybatis-spring-boot-starter

專案結構

通過Spring Initializr或Spring Boot CLI建立專案結構後,將pom.xml的相關專案修改為如下內容

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifacId>
  <version>2.3.1.RELEASE</version>
  <relativePath/>
</parent>

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
  </dependency>

  <!-- 下面為自定義Starter的依賴項 -->
</dependencies>

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <configuration>
	<source>1.8</source>
	<target>1.8</target>
      </configuration>
    </plugin>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-source-plugin</artifactId>
      <version>2.4</version>
      <executions>
	<execution>
	  <goals>
	    <goal>jar</goal>
	  </goals>
	</execution>
      </executions>
    </plugin>
  </plugins>
</build>

在starter中我們會定義SpringBean的註冊配置和屬性配置,如ESB訂閱服務的配置專案為

@Configuration
@EnableConfigurationProperties({EsbServerProperties.class})
public class EsbServerConfiguration {
    @Bean
    public SpringBus springBus(){
        return new SpringBus();
    }

    @Bean
    public LoggingFeature loggingFeature(){
        return new LoggingFeature();
    }

    @Bean
    public List<JMSConfigFeature> jmsConfigFeatures(EsbServerProperties props) throws JMSException {
        List<JMSConfigFeature> features = new ArrayList<>();
          
        /** 
         * 這裡會使用EsbServerProperties的屬性構建Bean例項
         */

        return features;
    }
}

屬性配置項

// 從application.yml等配置檔案中讀取並繫結esb.server.destination等屬性值
@Data
@ConfigurationProperties("esb.server")
public class EsbServerProperties {
    String destination;
    int currConsumers = 1;
    String channel;
    int ccsid = 1205;
    int transportType = 1;
    List<String> connectionNameLists;
    boolean replyError = false;
    String replySuccessText = "Success";
    String replyErrorText = "Failure";
}

到這裡我們已經完成一個基本的starter的功能

  1. 通過@ConfigurationProperties定義該starter註冊bean時需要的屬性集合
  2. 通過@Configuration定義該starter註冊的bean

但引用該starter的專案要如何啟用配置呢?其實有兩種方式,分別為手動和自動,其中我們會著重講解自動啟用配置。

手動啟用配置

所謂手動啟用配置其實就是在SpringBoot入口類上新增啟用配置用的自定義註解,針對上面的EsbServerConfiguration我們可以自定義EnableESBSrv註解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({EsbServerConfiguration.class})
public @interface EnableEsbSrv {
}

然後入口類的@SpringBootApplication註解前後新增@EnableEsbSrv即可。

讓人省心省力的自動啟用配置

自動啟用配置即只需在pom.xml中引入所依賴的starter,然後啟用應用即可自動啟用該starter的@Configuration所註解的類從而註冊Bean和讀取屬性配置。
而這一切都是由AutoConfigurationImportSelector來操刀,而我們可以通過@EnableAutoConfiguration@SpringBootApplication等例項化AutoConfigurationImportSelector類,配合菜譜resources/META-INF/spring.factories實現自動化配置的功能。
具體手法就是:將EsbServerConfiguration的全限類名稱寫在resources/META-INF/spring.factories的org.springframework.boot.autoconfigure.EnableAutoConfiguration下, 若存在多個則用逗號分隔。

org.springframework.boot.autoconfigure.EnableAutoConfiguration = \
com.john.starter.EsbServerConfiguration,\
com.john.starter.OtherConfiguration

好與更好——整合IDE智慧提示

應用啟動時會將application.yml中對應的配置項繫結到@ConfigurationProperties標註的類例項上,那麼對於應用開發人員而言日常工作就是修改application.yml的配置項。但IDE又缺少配置項的智慧提示,那就很低效了。幸虧Spring Boot早就為我們提供好解決方案,分為手工和自動兩種。為了效率當然是可以自動就不用手動的了。

Starter專案的工作

  1. 引入spring-boot-configuration-processor依賴項;
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-configuration-processor</artifactId>
  <optional>true</optional>
</dependency>
  1. 若src/resources/META-INF/spring-configuration-metadata.json不存在,那麼執行mvn compile時會生成target/classes/META-INF/spring-configuration-metadata.json;
  2. 複製target/classes/META-INF/spring-configuration-metadata.json到src/resources/META-INF/spring-configuration-metadata.json即可。

業務系統專案的工作

  1. 引入spring-boot-configuration-processor依賴項;
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-configuration-processor</artifactId>
  <optional>true</optional>
</dependency>
  1. IDEA安裝Spring Assistant外掛,並啟用Enable annotation processing(勾選 Settings/Build, Execution & Deployment/Compiles/Annotation Processors/Enable annotation processing)。

總結

spring-boot-starter非常適合用於團隊的技術積累和沉澱,不過想恰到好處地應用起來,不僅要需要深入Spring內部原理還要梳理清楚業務邏輯。後續我們再深入探討Spring核心的事情吧!

轉載請註明來自:https://www.cnblogs.com/fsjohnhuang/p/13956039.html —— ^_^肥仔John

相關文章