開源:如何自定義spring boot starter
本文demo: https://github.com/flyhero/easy-log
1. 機制
starter 是 SpringBoot 中一種非常重要的機制,它可以繁雜的配置統(tǒng)一集成到 starter 中,我們只需要通過 maven 將 starter 依賴引入到項目中,SpringBoot 就能自動掃描并加載相應(yīng)的默認配置。starter 的出現(xiàn)讓開發(fā)人員從繁瑣的框架配置中解放出來,將更多的精力專注于業(yè)務(wù)邏輯的開發(fā),極大的提高了開發(fā)效率。
2. 為什么要自定義starter
如今我們的服務(wù)幾乎都是基于Spring Boot構(gòu)建而來,我們可以將一些可獨立于業(yè)務(wù)代碼之外的功能和配置模塊封裝成一個個starter,SpringBoot會為我們完成自動裝配,這樣復(fù)用的時候只需要將其在pom中引用依賴即可。
3. 命名規(guī)則
為了區(qū)分官方提供的和第三方提供的,官方建議:
SpringBoot官方提供的 starter 以 spring-boot-starter-xxx 的形式命名,例如:
spring-boot-starter-aop spring-boot-starter-data-jdbc 第三方自定義的 starter 使用 xxx-spring-boot-starter 的形式命名,例如 :
mybatis-spring-boot-starter druid-spring-boot-starter
4. 創(chuàng)建步驟
自定義 starter 可以分為以下幾步:
創(chuàng)建工程 添加 POM 依賴 定義 propertie 類 定義 Service 類 定義配置類 創(chuàng)建 spring.factories 文件 構(gòu)建 starter 驗證
4.1 創(chuàng)建工程
使用 IntelliJ IDEA 創(chuàng)建一個空項目(Empty Project),如下圖。

點擊下圖中+號,通過Spring Initializr 創(chuàng)建兩個Spring Boot模塊,一個 hello-spring-boot-starter 和一個 hello-example。 
4.2 添加 POM 依賴
在 hello-spring-boot-starter 中 pom.xml 中添加如下依賴:
<--?核心啟動器,包含自動配置,日志及yaml?-->
<dependency>
? <groupId>org.springframework.bootgroupId>
????<artifactId>spring-boot-starterartifactId>
dependency>
4.3 定義 properties類
如果我們需要從 application.yaml 或 application.properties 中拿到一些使用者配置的數(shù)據(jù),那么我們就需要定義一個properties類。這個properties類主要作用是將 application.yaml 或 application.properties 中的配置信息映射成實體類,比如我們這里指定 prefix = "hello.test" 這樣,我們就能將以hello.test為前綴的配置項拿到了。
這個注解不但能映射成String或基本類型的變量,還可以映射為List,Map等數(shù)據(jù)結(jié)構(gòu)。
@ConfigurationProperties(prefix?="hello.test")
public?class?HelloProperties?{
????private?boolean?enable;
????private?String?name;
????private?String?url;
}
4.4 定義 Service 類
這個類不是自定義starter必須的,如果不需要定義上面的properties,那么這個Service類也不需要, 所以這個Service的目的是使用上面定義的properties類或供外部調(diào)用。
public?class?HelloService?{
????@Autowired
????private?HelloProperties?helloProperties;
????public?String?sayHello()?{
????????return?"hello?"+?helloProperties.getName()?+?"?welcome?to?my?homepage:"?+?helloProperties.getUrl();
????}
}
4.5 定義配置類
HelloAutoConfiguration 使用了以下 5 個注解:
@Configuration:表示該類是一個配置類; @EnableConfigurationProperties(xxxProperties.class):該注解的作用是為 xxxProperties 開啟屬性配置功能,并將這個類以組件的形式注入到容器中; @ConditionalOnProperty(prefix = "xxx", name= "x", matchIfMissing = true) : 當(dāng)指定的配置項等于你想要的時候,配置類生效; @ConditionalOnMissingBean(xxx.class):該注解表示當(dāng)容器中沒有 xxx 類時,該方法才生效; @Bean:該注解用于將方法的返回值以 Bean 對象的形式添加到容器中。
@Configuration
@EnableConfigurationProperties(HelloProperties.class)
@ConditionalOnProperty(prefix?=?"hello.test",?name?=?"enable",?matchIfMissing?=?true)
public?class?HelloAutoConfiguration?{
????
????@Bean
????@ConditionalOnMissingBean(HelloService.class)
????public?HelloService?helloService()?{
????????return?new?HelloService();
????}
}
4.6 創(chuàng)建 spring.factories文件
Spring Factories 機制是 Spring Boot 中的一種服務(wù)發(fā)現(xiàn)機制,這種擴展機制與 Java SPI 機制十分相似。Spring Boot 會自動掃描所有 Jar 包類路徑下 META-INF/spring.factories 文件,并讀取其中的內(nèi)容,進行實例化,這種機制也是 Spring Boot Starter 的基礎(chǔ)。因此我們自定義 starter 時,需要在項目類路徑下創(chuàng)建一個 spring.factories 文件。
在 hello-spring-boot-starter 的路徑下(resources )中創(chuàng)建一個 META-INF 文件夾,并在 META-INF 文件夾中創(chuàng)建一個 spring.factories 文件。

將 Spring Boot 的 EnableAutoConfiguration 接口與自定義 starter 的自動配置類 HelloAutoConfiguration 組成一組鍵值對添加到 spring.factories 文件中,以方便 Spring Boot 在啟動時,獲取到自定義 starter 的自動配置:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.hello.starter.config.HelloAutoConfiguration
4.7 構(gòu)建starter
Terminal 下進入到 ?hello-spring-boot-starter 下執(zhí)行 mvn clean install 或者 如圖:

5. 驗證
5.1 添加依賴
在hello-example下pom.xml中添加我們自定義的 hello-spring-boot-starter:
????org.springframework.boot
????spring-boot-starter-web
????com.example
????hello-spring-boot-starter
????0.0.1-SNAPSHOT
5.2 配置信息
在 application.yaml 或 application.properties 中配置如下:
hello.test.enable=true
hello.test.name=Mr.Wang
hello.test.url=https://github.com/flyhero
5.3 創(chuàng)建controller類
@RestController
public?class?HelloController?{
????@Autowired
????private?HelloService?helloService;
????@GetMapping("/test")
????public?String?test(){
????????return?helloService.sayHello();
????}
}
5.4 請求接口
從相應(yīng)的結(jié)果可知,我們定義的starter已經(jīng)生效了。

6. demo
本文demo可參考:https://github.com/flyhero/easy-log
