1. 程式人生 > >手把手教你實現自定義Spring Boot的 Starter

手把手教你實現自定義Spring Boot的 Starter

### 引言 上篇文章[《天天用SpringBoot,它的自動裝配原理卻說不出來》](https://mp.weixin.qq.com/s/TnofWzuaH-WDcfYVfp-UoA)我們有說`springBoot`的自動裝配怎麼實現的(建議最好先看下篇文章,因為前後有關係),這篇文章的話我們就自己來實現一個`SpringBoot`的 `starter`吧。廢話不多說我們還是直入主題吧。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200802003847983.png) 什麼是`Spring Boot Starter`呢?我們直接來看看官網是怎麼介紹的吧。 >Starters are a set of convenient dependency descriptors that you can include in your application. You get a one-stop shop for all the Spring and related technologies that you need without having to hunt through sample code and copy-paste loads of dependency descriptors. For example, if you want to get started using Spring and JPA for database access, include the spring-boot-starter-data-jpa dependency in your project. > 納尼,一大堆的英文,這還有興趣接著往下看嗎?是不是看到這直接退出了。都到門口了,不進來喝杯茶再走嘛?看都看到這了還是接著繼續往下看吧。我們先不解釋這一段話是什麼意思,我們可以看看`starter`的出現給我們解決了什麼問題。 我們還是以上述官網的例子來進行說明比如說我們需要在`Spring` 中適應`JPA`來操作資料庫。 在沒有`springBoot-starter`之前,我們需要引入`jpa`的步驟 - 通過`maven` 引入jdbc的依賴、以及jpa相關的各種依賴 - 編寫`jpa`相關的配置檔案 - 網上各種查詢找資料進行除錯,除錯的過程對於新手可能會有點奔潰會遇到各種奇奇怪怪的問題,`jar`包衝突啊,這個`jar`包下載不下來,缺少某個`jar`包。 - 終於在經歷千辛萬苦,哼次哼次的解決各種問題之後終於把專案跑起來了,然後把這次整合`jpa`遇到的問題,以及整合的步驟都一一的詳細記錄下來。方便下次在需要整合`jpa`的時候直接`copy`就好了。 我們以前在沒有`starter`之前是不是都是這麼玩的。這樣的缺點是不是也非常顯著,比如過程複雜、需要不停的貼上複製(不過這是程式設計師經常乾的事情了,也不在乎多一兩次了)、整合其它元件到自己的專案變的困難,效率低下。這也就造成了`996`的程式設計師比較多了(晚上就不能夠回去`69`了)。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200801235345500.png) ### SpringBoot Starter的出現 我們可以看下`SpringBoot` 現在都為我們提供有哪些`starter`,我這邊這截圖了部分`starter`,更多的請點選https://github.com/spring-projects/spring-boot/tree/master/spring-boot-project/spring-boot-starters ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200729151737421.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3plbmdmYW53ZWkxOTkw,size_16,color_FFFFFF,t_70) `starter`的實現:雖然我們每個元件的`starter`實現各有差異,但是它們基本上都會使用到兩個相同的內容:`ConfigurationProperties`和`AutoConfiguration`。因為`Spring Boot`提倡“**約定大於配置**”這一理念,所以我們使用`ConfigurationProperties`來儲存我們的配置,並且這些配置都可以有一個預設值,即在我們沒有主動覆寫原始配置的情況下,預設值就會生效。除此之外,`starter`的`ConfigurationProperties`還使得所有的配置屬性被聚集到一個檔案中(一般在`resources`目錄下的`application.properties`),這樣我們就告別了`Spring`專案中`XML`地獄。 `starter`的出現幫把我們把各種複雜的配置都封裝起來了,讓我們真正的可以達到了開箱即用。不僅降低了我們使用它的門檻,並且還大大提高了我們的開發效率。正如前面所說[《SpringBoot自動裝配》](https://mp.weixin.qq.com/s/TnofWzuaH-WDcfYVfp-UoA)讓我們有更多的時間去陪女朋友。 ### 實現自己的SpringBoot Starter #### 命名規範 如果你快有孩子了,出生前你比較急的一定是起個名字。孩子的姓名標識著你和你愛人的血統,一定不會起隔壁老王的姓氏,肯定會招來異樣的眼光。在`maven`中,`groupId`代表著姓氏,`artifactId`代表著名字。`Spring Boot`也是有一個命名的建議的。所以名字是不能夠隨隨便便取得,可以按照官方的建議來取。 >What’s in a name All official starters follow a similar naming pattern; spring-boot-starter-*, where * is a particular type of application. This naming structure is intended to help when you need to find a starter. The Maven integration in many IDEs lets you search dependencies by name. For example, with the appropriate Eclipse or STS plugin installed, you can press ctrl-space in the POM editor and type “spring-boot-starter” for a complete list. As explained in the “Creating Your Own Starter” section, third party starters should not start with spring-boot, as it is reserved for official Spring Boot artifacts. Rather, a third-party starter typically starts with the name of the project. For example, a third-party starter project called thirdpartyproject would typically be named thirdpartyproject-spring-boot-starter. 大概意思是 官方的 `starter` 的命名格式為 `spring-boot-starter-{xxxx}` 比如`spring-boot-starter-activemq` 第三方我們自己的命名格式為 `{xxxx}-spring-boot-starter`。比如`mybatis-spring-boot-starter`。 如果我們忽略這種約定,是不是會顯得我們寫的東西不夠“專業“。 #### 自定義一個Starter 下面我們就來實現一個自定義的傳送簡訊的starter,命名為`sms-spring-boot-starter`。 1. **引入`pom`** ```xml ``` 2. **編寫配置檔案** 發簡訊我們需要配置一些賬號資訊,不同的簡訊供應商,賬戶資訊是不一樣的,所以我們需要定義一`個XXXXProperties` 來自動裝配這些賬戶資訊。下面我們就以騰訊雲和阿里雲兩家供應商為例; ```java @ConfigurationProperties(prefix = "sms") @Data public class SmsProperties { private SmsMessage aliyun = new SmsMessage(); private SmsMessage tencent = new SmsMessage(); @Data public static class SmsMessage{ /** * 使用者名稱 */ private String userName; /** * 密碼 */ private String passWord; /** * 祕鑰 */ private String sign; /** * */ private String url; @Override public String toString() { return "SmsMessage{" + "userName='" + userName + '\'' + ", passWord='" + passWord + '\'' + ", sign='" + sign + '\'' + ", url='" + url + '\'' + '}'; } } } ``` 如果需要在其他專案中使用傳送簡訊功能的話,我們只需要在配置檔案(`application.yml`)中配置`SmsProperties` 的屬性資訊就可以了。 比如: ```java sms: aliyun: pass-word: 12345 user-name: java金融 sign: 阿里雲 url: http://aliyun.com/send tencent: pass-word: 6666 user-name: java金融 sign: 騰訊雲 url: http://tencent.com/send ``` 還記的`@ConfigurationProperties`註解裡面是不是有個`prefix` 屬性,我們配置的這個屬性是`sms`,配置這個的主要一個作用的話是主要用來區別各個元件的引數。這裡有個小知識點需要注意下當我們在配置檔案輸入`sms`我們的`idea`會提示這個`sms`有哪些屬性可以配置,以及每個屬性的註釋都有標記,建議的話註釋還是寫英文,這樣會顯得你比較專業。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200731152320326.png) 這個提示的話,是需要引入下面這個`jar`的。 ```xml ``` 引入這個`jar`之後,我們編譯之後就會在`META-INF`資料夾下面生成一個`spring-configuration-metadata.json`的檔案。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200731153010961.png) 我們可以看到這個檔案其實 是根據SmsProperties類的成員屬性來生成的。 3. **然後在編寫簡訊自動配置類:** ```java @EnableConfigurationProperties(value = SmsProperties.class) @Configuration public class SmsAutoConfiguration { /** * 阿里雲傳送簡訊的實現類 * @param smsProperties * @return */ @Bean public AliyunSmsSenderImpl aliYunSmsSender(SmsProperties smsProperties){ return new AliyunSmsSenderImpl(smsProperties.getAliyun()); } /** * 騰訊雲傳送簡訊的實現類 * @param smsProperties * @return */ @Bean public TencentSmsSenderImpl tencentSmsSender(SmsProperties smsProperties){ return new TencentSmsSenderImpl(smsProperties.getTencent()); } } ``` 編寫我們的傳送簡訊實現類: ```java public class AliyunSmsSenderImpl implements SmsSender { private SmsMessage smsMessage; public AliyunSmsSenderImpl(SmsMessage smsProperties) { this.smsMessage = smsProperties; } @Override public boolean send(String message) { System.out.println(smsMessage.toString()+"開始傳送簡訊==》簡訊內容:"+message); return true; } } ``` 4. **讓starter生效** `starter`整合應用有兩種方式: - 被動生效 我們首先來看下我們熟悉的方式,通過`SpringBoot`的`SPI`的機制來去載入我們的starter。我們需要在`META-INF`下新建一個`spring.factories`檔案`key`為`org.springframework.boot.autoconfigure.EnableAutoConfiguration, value`是我們的`SmsAutoConfiguration` 全限定名(**記得去除前後的空格,否則會不生效**)。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/2020073116194076.png) - 主動生效 在`starter`元件整合到我們的`Spring Boot`應用時需要主動宣告啟用該`starter`才生效,通過自定義一個`@Enable`註解然後在把自動配置類通過`Import`註解引入進來。 ```java @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Import({SmsAutoConfiguration.class}) public @interface EnableSms { } ``` 使用的時候需要在啟動類上面開啟這個註解。 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200731164241293.png) 5.**打包,部署到倉庫** 如果是本地的話,直接通過`mvn install`命令就可以了。 如果需要部署到公司的倉庫話,這個就不說了。 6. **新建一個新的`SpringBoot`專案引入我們剛寫的`starter`** ```java ``` 在專案配置檔案配上簡訊賬號資訊 ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200731173654747.png) 測試程式碼 ```java @SpringBootApplication @EnableSms public class AutoconfigApplication { public static void main(String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(AutoconfigApplication.class, args); AliyunSmsSenderImpl aliyunSmsSender = applicationContext.getBean(AliyunSmsSenderImpl.class); aliyunSmsSender.send("用阿里雲傳送簡訊"); TencentSmsSenderImpl tencentSmsSender = applicationContext.getBean(TencentSmsSenderImpl.class); tencentSmsSender.send("用騰訊雲傳送簡訊"); } ``` 執行結果: ```java SmsMessage{userName='java金融', passWord='12345', sign='阿里雲', url='http://aliyun.com/send'}開始傳送簡訊==》簡訊內容:用阿里雲傳送簡訊 SmsMessage{userName='java金融', passWord='6666', sign='騰訊雲', url='http://tencent.com/send'}開始傳送簡訊==》簡訊內容:用騰訊雲傳送簡訊 ``` 至此的話我們自定義的一個`starter`就已經完成了,這個`starter`只是一個演示的`demo`,程式碼有點粗糙,專案結構也有點問題。重點看下這個實現原理就好。趕緊動動小手去實現一個自己的`starter`吧。 ### 總結 - `SpringBoot starter`的出現,讓我們專案中整合其他元件變得簡單。它把簡單給了別人,把複雜留給了自己。“犧牲小我,成就大我”的思想還是值得學習的。平時我們工作中,比如要開發一個元件、或者一個工具類,也應該儘可能的讓使用方可以做到無腦使用,不要搞的太複雜,又能讓使用者可以靈活擴充套件。 ### 結束 - 由於自己才疏學淺,難免會有紕漏,假如你發現了錯誤的地方,還望留言給我指出來,我會對其加以修正。 - 如果你覺得文章還不錯,你的轉發、分享、讚賞、點贊、留言就是對我最大的鼓勵。 - 感謝您的閱讀,十分歡迎並感謝您的關注。 站在巨人的肩膀上摘蘋果: https://www.cnblogs.com/tjudzj/p/8758391.html https://blog.springlearn.cn/post