版權聲明:該文轉自: http://www.nosuchfield.com/2017/10/15/Spring-Boot-Starters/。版權歸原創作者,在此對原作者的付出表示感謝!
starter是SpringBoot中的一個新發明,它有效的降低了項目開發過程的復雜程度,對於簡化開發操作有着非常好的效果。本文轉載了一片文章,詳細介紹了spring boot stater是什么?它的作用是什么?
Spring Boot Starter是在SpringBoot組件中被提出來的一種概念,stackoverflow上面已經有人概括了這個starter是什么東西,想看完整的回答戳這里(https://stackoverflow.com/questions/28273543/what-are-spring-boot-starter-jars/28273660#28273660)

大概意思就是說starter是一種對依賴的synthesize(合成),這是什么意思呢?我可以舉個例子來說明。
傳統的做法
在沒有starter之前,假如我想要在Spring中使用jpa,那我可能需要做以下操作:
- 在Maven中引入使用的數據庫的依賴(即JDBC的jar)
- 引入jpa的依賴
- 在xxx.xml中配置一些屬性信息
- 反復的調試直到可以正常運行
需要注意的是,這里操作在我們每次新建一個需要用到jpa的項目的時候都需要重復的做一次。也許你在第一次自己建立項目的時候是在Google上自己搜索了一番,花了半天時間解決掉了各種奇怪的問題之后,jpa終於能正常運行了。有些有經驗的人會在OneNote上面把這次建立項目的過程給記錄下來,包括操作的步驟以及需要用到的配置文件的內容,在下一次再創建jpa項目的時候,就不需要再次去Google了,只需要照着筆記來,之后再把所有的配置文件copy&paste就可以了。
像上面這樣的操作也不算不行,事實上我們在沒有starter之前都是這么干的,但是這樣做有幾個問題:
- 如果過程比較繁瑣,這樣一步步操作會增加出錯的可能性
- 不停地copy&paste不符合Don’t repeat yourself精神
- 在第一次配置的時候(尤其如果開發者比較小白),需要花費掉大量的時間
使用Spring Boot Starter提升效率
starter的主要目的就是為了解決上面的這些問題。
starter的理念:starter會把所有用到的依賴都給包含進來,避免了開發者自己去引入依賴所帶來的麻煩。需要注意的是不同的starter是為了解決不同的依賴,所以它們內部的實現可能會有很大的差異,例如jpa的starter和Redis的starter可能實現就不一樣,這是因為starter的本質在於synthesize,這是一層在邏輯層面的抽象,也許這種理念有點類似於Docker,因為它們都是在做一個“包裝”的操作,如果你知道Docker是為了解決什么問題的,也許你可以用Docker和starter做一個類比。
starter的實現:雖然不同的starter實現起來各有差異,但是他們基本上都會使用到兩個相同的內容:ConfigurationProperties和AutoConfiguration。因為Spring Boot堅信“約定大於配置”這一理念,所以我們使用ConfigurationProperties來保存我們的配置,並且這些配置都可以有一個默認值,即在我們沒有主動覆寫原始配置的情況下,默認值就會生效,這在很多情況下是非常有用的。除此之外,starter的ConfigurationProperties還使得所有的配置屬性被聚集到一個文件中(一般在resources目錄下的application.properties),這樣我們就告別了Spring項目中XML地獄。
starter的整體邏輯:

上面的starter依賴的jar和我們自己手動配置的時候依賴的jar並沒有什么不同,所以我們可以認為starter其實是把這一些繁瑣的配置操作交給了自己,而把簡單交給了用戶。除了幫助用戶去除了繁瑣的構建操作,在“約定大於配置”的理念下,ConfigurationProperties還幫助用戶減少了無謂的配置操作。並且因為 application.properties 文件的存在,即使需要自定義配置,所有的配置也只需要在一個文件中進行,使用起來非常方便。
了解了starter其實就是幫助用戶簡化了配置的操作之后,要理解starter和被配置了starter的組件之間並不是競爭關系,而是輔助關系,即我們可以給一個組件創建一個starter來讓最終用戶在使用這個組件的時候更加的簡單方便。基於這種理念,我們可以給任意一個現有的組件創建一個starter來讓別人在使用這個組件的時候更加的簡單方便,事實上Spring Boot團隊已經幫助現有大部分的流行的組件創建好了它們的starter,你可以在這里查看這些starter的列表。
創建自己的Spring Boot Starter
如果你想要自己創建一個starter,那么基本上包含以下幾步
- 創建一個starter項目,關於項目的命名你可以參考這里
- 創建一個ConfigurationProperties用於保存你的配置信息(如果你的項目不使用配置信息則可以跳過這一步,不過這種情況非常少見)
- 創建一個AutoConfiguration,引用定義好的配置信息;在AutoConfiguration中實現所有starter應該完成的操作,並且把這個類加入spring.factories配置文件中進行聲明
- 打包項目,之后在一個SpringBoot項目中引入該項目依賴,然后就可以使用該starter了
我們來看一個例子(例子的完整代碼位於https://github.com/RitterHou/learn-spring-boot-starter)
首先新建一個Maven項目,設置 pom.xml 文件如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 5 <modelVersion>4.0.0</modelVersion> 6 <artifactId>http-starter</artifactId> 7 <version>0.0.1-SNAPSHOT</version> 8 9 <!-- 自定義starter都應該繼承自該依賴 --> 10 <!-- 如果自定義starter本身需要繼承其它的依賴,可以參考 https://stackoverflow.com/a/21318359 解決 --> 11 <parent> 12 <groupId>org.springframework.boot</groupId> 13 <artifactId>spring-boot-starters</artifactId> 14 <version>1.5.2.RELEASE</version> 15 </parent> 16 17 <dependencies> 18 <!-- 自定義starter依賴此jar包 --> 19 <dependency> 20 <groupId>org.springframework.boot</groupId> 21 <artifactId>spring-boot-starter</artifactId> 22 </dependency> 23 <!-- lombok用於自動生成get、set方法 --> 24 <dependency> 25 <groupId>org.projectlombok</groupId> 26 <artifactId>lombok</artifactId> 27 <version>1.16.10</version> 28 </dependency> 29 </dependencies> 30 31 </project>
創建proterties類來保存配置信息:
1 @ConfigurationProperties(prefix = "http") // 自動獲取配置文件中前綴為http的屬性,把值傳入對象參數 2 @Setter 3 @Getter 4 public class HttpProperties { 5 6 // 如果配置文件中配置了http.url屬性,則該默認屬性會被覆蓋 7 private String url = "http://www.baidu.com/"; 8 9 }
上面這個類就是定義了一個屬性,其默認值是 http://www.baidu.com/,我們可以通過在 application.properties中添加配置 http.url=https://www.zhihu.com 來覆蓋參數的值。
創建業務類:
1 @Setter 2 @Getter 3 public class HttpClient { 4 5 private String url; 6 7 // 根據url獲取網頁數據 8 public String getHtml() { 9 try { 10 URL url = new URL(this.url); 11 URLConnection urlConnection = url.openConnection(); 12 BufferedReader br = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "utf-8")); 13 String line = null; 14 StringBuilder sb = new StringBuilder(); 15 while ((line = br.readLine()) != null) { 16 sb.append(line).append("\n"); 17 } 18 return sb.toString(); 19 } catch (Exception e) { 20 e.printStackTrace(); 21 } 22 return "error"; 23 } 24 25 }
這個業務類的操作非常簡單,只包含了一個 url 屬性和一個 getHtml 方法,用於獲取一個網頁的HTML數據,讀者看看就懂了。
創建AutoConfiguration
1 @Configuration 2 @EnableConfigurationProperties(HttpProperties.class) 3 public class HttpAutoConfiguration { 4 5 @Resource 6 private HttpProperties properties; // 使用配置 7 8 // 在Spring上下文中創建一個對象 9 @Bean 10 @ConditionalOnMissingBean 11 public HttpClient init() { 12 HttpClient client = new HttpClient(); 13 14 String url = properties.getUrl(); 15 client.setUrl(url); 16 return client; 17 } 18 19 }
在上面的AutoConfiguration中我們實現了自己要求:在Spring的上下文中創建了一個HttpClient類的bean,並且我們把properties中的一個參數賦給了該bean。
關於@ConditionalOnMissingBean 這個注解,它的意思是在該bean不存在的情況下此方法才會執行,這個相當於開關的角色,更多關於開關系列的注解可以參考這里。
最后,我們在 resources 文件夾下新建目錄 META-INF,在目錄中新建 spring.factories 文件,並且在 spring.factories 中配置AutoConfiguration:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.nosuchfield.httpstarter.HttpAutoConfiguration
到此,我們的starter已經創建完畢了,使用Maven打包該項目。之后創建一個SpringBoot項目,在項目中添加我們之前打包的starter作為依賴,然后使用SringBoot來運行我們的starter,代碼如下:
1 @Component 2 public class RunIt { 3 4 @Resource 5 private HttpClient httpClient; 6 7 public void hello() { 8 System.out.println(httpClient.getHtml()); 9 } 10 11 }
正常情況下此方法的執行會打印出url http://www.baidu.com/ 的HTML內容,之后我們在application.properties中加入配置:
http.url=https://www.zhihu.com/
再次運行程序,此時打印的結果應該是知乎首頁的HTML了,證明properties中的數據確實被覆蓋了。
