最詳細的自定義Spring Boot Starter開發教程


1. 前言

隨着Spring的日漸臃腫,為了簡化配置、開箱即用、快速集成,Spring Boot 橫空出世。 目前已經成為 Java 目前最火熱的框架了。平常我們用Spring Boot開發web應用。Spring mvc 默認使用tomcat servlet容器, 因為Spring mvc組件集成了spring-boot-starter-tomcat 。但是現在undertow servlet容器的性能非常好。我們可以通過以下方式先排除tomcat:

然后直接替換為undertow:

代碼無需更改。這就是組件化后的好處:1.可插拔。2.可定制。3.按需集成。為什么能夠做到快速適配?我們試想一個這樣一個場景:假如你的汽車輪子上有個螺絲壞了,你要買一個螺絲去自己裝。你去店里只要報上你汽車的品牌和位置老板就能准確地知道你要用哪種螺絲。這就是標准已經制定好的好處。如果沒有標准,你很容易買到不配套的螺絲,你要不停的試錯。這顯然不是你想要的。 如果把這種標准潛移默化,那么我們在溝通上就更加快捷方便。有時候你女朋友一個眼神你就知道她想要干什么。所以Spring Boot 有一個“約定大於配置”的規則,讓程序組件之間來減少配置,降低復雜性。因此你在開發一個自定義的Spring Boot Starter的時候也最好考慮你的starter如何達到以上的便利性。

2. Spring Boot的一些約定

一個組件的設計一定要有標准和規則。Spring Boot Starter也不例外。我們來看看一些常規的做法。

2.1 命名風格

如果你快有孩子了,出生前你比較急的一定是起個名字。姓名標識着你和你愛人的血統,一定不會起隔壁老王的姓氏,肯定會招來異樣的眼光。在maven中,groupId代表着姓氏,artifactId代表着名字。Spring Boot也是有一個命名的建議的。groupId不要用官方的org.springframework.boot
而要用你自己獨特的。對於artifactId的命名,Spring Boot官方建議非官方的Starter命名格式遵循 xxxx-spring-boot-starter ,例如 mybatis-spring-boot-starter 。官方starter會遵循spring-boot-starter-xxxx ,例如上面提到的spring-boot-starter-undertow 。很多開源starter作者會忽略這種約定,顯得不夠“專業“。

3. 自定義一個Starter

接下來我們構建一個自定義的第三方短信starter,命名為sms-spring-boot-starter 。有一些細節問題需要邊寫邊來介紹。下面是一個省略了samples和test模塊模版:

依據上面我們建立如下項目:

3.1 sms-spring-boot

sms-spring-boot構建一個項目重要的就是依賴管理。所以引入BOM是必要的。主要管理該starter的所有模塊module,以及starter的所有依賴甚至sms-spring-boot-autoconfigure都由sms-spring-boot管理。

3.2 sms-spring-boot-autoconfigure

該模塊主要用來定義配置參數、以及自動配置對外暴露的功能(一般是抽象的接口Spring Bean)。

3.2.1 配置參數

一般配置參數都是在Spring Boot 的application.yml中。我們會定義一個前綴標識來作為名稱空間隔離各個組件的參數。對應的組件會定義一個XXXXProperties 來自動裝配這些參數。自動裝配的機制基於@ConfigurationProperties注解,請注意一定要顯式聲明你配置的前綴標識(prefix)。我們的sms-spring-boot會作如下配置:

c997518d5e8dba9a9bb69dd23a0770d8.png

以上以阿里雲的短信功能為例作配置,在將來使用時只需要在application.yml中加入上面對應SmsProperties的配置:

302dd03f038782022ec8cf43168620ca.png

如果你集成了Spring Boot 校驗庫 你也可以對SmsProperties進行校驗。在配置application.yml時細心的java開發者會發現參數配置都有像下面一樣的參數描述:
8092aac794d4b77ca959909c3af789dd.png

就像java中的注釋一樣方便我們理解該配置的作用,其實這個就是java注釋生成的。你需要依賴

8092aac794d4b77ca959909c3af789dd.png

然后就該依賴會對SmsProperties 成員屬性的注釋進行提取生成一個spring-configuration-metadata.json文件,這就是配置描述的元數據文件。Spring Boot官方也對注釋進行了一些規則約束:

  • 不要以“The”或“A”開頭描述。
  • 對於boolean類型,請使用“Whether" 或“Enable”開始描述。
  • 對於基於集合的類型,請使用“Comma-separated list”
  • 如果默認時間單位不等同於毫秒,則使用java.time.Duration而不是long描述默認單位,例如“如果未指定持續時間后綴,則將使用秒”。
  • 除非必須在運行時確定,否則不要在描述中提供默認值。

補充我個人建議描述盡量使用英文描述。

3.2.2 配置自動暴露功能接口

拿到配置后,接下來就是根據配置來初始化我們的功能接口,我們會抽象一個短信發送接口SmsSender,根據短信提供方的SDK來進行功能設計。請注意autoconfigure模塊的依賴幾乎都是不可傳遞的。也就是依賴坐標配置optional為true 。
功能接口實現完后我們會編寫一個自動配置類 SmsAutoConfiguration 。除了@Configuration注解外,@ConfigurationProperties會幫助我們將我們的配置類SmsProperties加載進來。然后將我們需要暴露的功能接口聲明為Spring Bean 暴露給Spring Boot應用 。有時候我們還可以通過一些條件來控制SmsAutoConfiguration或者SmsSender ,比如根據某個條件是否加載或加載不同的SmsSender。有時間你可以看看redis-starter就能很明顯感覺到,它會根據luttuce、redisson、jedis 的變化實例化不同的客戶端鏈接。實現方式是使用了@Conditional系列注解,有時間可以學習一下該系列的注解。好了我們的SmsAutoConfiguration聲明如下:

a9204a6d80a3df1a7e1a2ac7704c3664.png

3.2.3 主動生效和被動生效

starter集成入應用有兩種方式。我們從應用視角來看有兩種:

  • 一種是主動生效,在starter組件集成入Spring Boot應用時需要你主動聲明啟用該starter才生效,即使你配置完全。這里會用到@Import注解,將該注解標記到你自定義的@Enable注解上:
    be07d9a2aa637b267ae9cba39b8b6064.png
    我們將該注解標記入Spring Boot應用就可以使用短信功能了。
  • 另一種被動生效,在starter組件集成入Spring Boot應用時就已經被應用捕捉到。這里會用到類似java的SPI機制。在autoconfigure資源包下新建META-INF/spring.factories寫入SmsAutoConfiguration全限定名。
    d3422497106918aadf5237c75f5d66ad.png

多個配置類逗號隔開,換行使用反斜杠。

3.3 sms-spring-boot-starter

該模塊是一個空jar。它唯一目的是提供必要的依賴項來使用starter。你可以認為它就是集成該starter功能的唯一入口。不要對添加啟動器的項目做出假設。如果您自動配置的依賴庫通常需要其他啟動器,請同時提及它們。如果可選依賴項的數量很高,則提供一組適當的默認依賴項可能很難,因為您應該避免包含對典型庫的使用不必要的依賴項。換句話說,您不應該包含可選的依賴項。
無論哪種方式,您的starter必須直接或間接引用核心Spring Boot啟動器(spring-boot-starter)(如果您的啟動器依賴於另一個啟動器,則無需添加它)。如果只使用自定義啟動器創建項目,則Spring Boot的核心功能將通過核心啟動器的存在來實現。
我們的sms-spring-boot-starter僅僅是以下的pom:

5f45659e22f942fde9c31ee6103bac21.png

到此為止,我們的整個短信Starter就開發完成了。

4.總結

自定義starter對於我們項目組件化、模塊化是有很大幫助的。同時也是Spring Boot一大特色。相信通過小胖的介紹你已經蠢蠢欲試了,那么就趕緊開始寫一個吧。如果覺得對你有用可以點個贊關注一下。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM