Spring Boot Starters是什么?


版權聲明:該文轉自: 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,那我可能需要做以下操作:

  1. 在Maven中引入使用的數據庫的依賴(即JDBC的jar)
  2. 引入jpa的依賴
  3. 在xxx.xml中配置一些屬性信息
  4. 反復的調試直到可以正常運行

  需要注意的是,這里操作在我們每次新建一個需要用到jpa的項目的時候都需要重復的做一次。也許你在第一次自己建立項目的時候是在Google上自己搜索了一番,花了半天時間解決掉了各種奇怪的問題之后,jpa終於能正常運行了。有些有經驗的人會在OneNote上面把這次建立項目的過程給記錄下來,包括操作的步驟以及需要用到的配置文件的內容,在下一次再創建jpa項目的時候,就不需要再次去Google了,只需要照着筆記來,之后再把所有的配置文件copy&paste就可以了。

  像上面這樣的操作也不算不行,事實上我們在沒有starter之前都是這么干的,但是這樣做有幾個問題:

  1. 如果過程比較繁瑣,這樣一步步操作會增加出錯的可能性
  2. 不停地copy&paste不符合Don’t repeat yourself精神
  3. 在第一次配置的時候(尤其如果開發者比較小白),需要花費掉大量的時間

  使用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,那么基本上包含以下幾步

  1. 創建一個starter項目,關於項目的命名你可以參考這里
  2. 創建一個ConfigurationProperties用於保存你的配置信息(如果你的項目不使用配置信息則可以跳過這一步,不過這種情況非常少見)
  3. 創建一個AutoConfiguration,引用定義好的配置信息;在AutoConfiguration中實現所有starter應該完成的操作,並且把這個類加入spring.factories配置文件中進行聲明
  4. 打包項目,之后在一個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中的數據確實被覆蓋了。


免責聲明!

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



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