一、SpringBoot的starter簡介
1.1 什麼是starter(場景啟動器)
在SpringBoot出現之前,如果我們想使用SpringMVC來建構我們的web項目,必須要做的幾件事情如下:
首先項目中需要引入SpringMVC的依賴
在web.xml中注冊SpringMVC的DispatcherServlet,并配置url映射
編寫springmcv-servlet.xml,在其中配置SpringMVC中幾個重要的元件,處理映射器(HandlerMapping)、處理擴充卡(HandlerAdapter)、視圖解析器(ViewResolver)
在applicationcontext.xml檔案中引入springmvc-servlet.xml檔案
…
以上這幾步隻是配置好了SpringMVC,如果我們還需要與資料庫進行互動,就要在application.xml中配置資料庫連接配接池DataSource,如果需要資料庫事務,還需要配置TransactionManager…
這就是使用Spring架構開發項目帶來的一些的問題:
依賴導入問題: 每個項目都需要來單獨維護自己所依賴的jar包,在項目中使用到什麼功能就需要引入什麼樣的依賴。手動導入依賴容易出錯,且無法統一集中管理
配置繁瑣: 在引入依賴之後需要做繁雜的配置,并且這些配置是每個項目來說都是必要的,例如web.xml配置(Listener配置、Filter配置、Servlet配置)、log4j配置、資料庫連接配接池配置等等。這些配置重複且繁雜,在不同的項目中需要進行多次重複開發,這在很大程度上降低了我們的開發效率
而在SpringBoot出現之後,它為我們提供了一個強大的功能來解決上述的兩個痛點,這就是SpringBoot的starters(場景啟動器)。
Spring Boot通過将我們常用的功能場景抽取出來,做成的一系列場景啟動器,這些啟動器幫我們導入了實作各個功能所需要依賴的全部元件,我們隻需要在項目中引入這些starters,相關場景的所有依賴就會全部被導入進來,并且我們可以抛棄繁雜的配置,僅需要通過配置檔案來進行少量的配置就可以使用相應的功能。
二、SpringBoot場景啟動器的原理
在導入的starter之後,SpringBoot主要幫我們完成了兩件事情:
相關元件的自動導入
相關元件的自動配置
這兩件事情統一稱為SpringBoot的自動配置
2.1 自動配置原理
2.1.1 自動配置類的擷取與注入
我們從主程式入口來探索一下整個過程的原理:
@SpringBootApplication //标注這個類是一個springboot的應用
public class CommunityApplication {
public static void main(String[] args) {
//将springboot應用啟動
SpringApplication.run(CommunityApplication.class, args);
}
}
Spring Boot 基礎就不介紹了,推薦下這個實戰教程:
https://github.com/javastacks/spring-boot-best-practice @SpringBootApplication注解内部結構如下圖所示:
結論:
SpringBoot在啟動的時候從類路徑下的META-INF/spring.factories中擷取EnableAutoConfiguration指定的所有自動配置類的全限定類名
将這些自動配置類導入容器,自動配置類就生效,幫我們進行自動配置工作;
整個J2EE的整體解決方案和自動配置都在spring-boot-autoconfigure的jar包中;
它會給容器中導入非常多的自動配置類 (xxxAutoConfiguration), 就是給容器中導入這個場景需要的所有元件,并配置好這些元件 ;
有了自動配置類,免去了我們手動編寫配置注入功能元件等的工作;
2.1.2 自動配置的過程
自動配置類被注入到容器當中後,會幫我們進行元件的自動配置和自動注入的工作,我們以HttpEncodingAutoConfiguration(Http編碼自動配置)為例解釋這個過程:
首先我們先看下SpringBoot中配置檔案與POJO類之間映射的方法,這是進行自動配置的基礎。
配置集中化管理:SpringBoot中所有可配置項都集中在一個檔案中(application.yml),這個檔案中的配置通過@ConfigurationProperties注解來與我們程式内部定義的POJO類來産生關聯,這些POJO類統一命名為xxxProperties,并且這些xxxProperties類中各個屬性字段都有自己的預設值,這也是SpringBoot約定大于配置理念的展現,盡可能減少使用者做選擇的次數,但同時又不失靈活性。隻要我們想,配置檔案中的配置随時可以覆寫預設值。
之後,通過配合@EnableConfigurationProperties注解,就可以自動将與配置檔案綁定好的這個類注入到容器中供我們使用。
自動配置類的工作流程:
根據限定的條件向容器中注入元件
使用xxxProperties對注入的元件的相關屬性進行配置
//表示這是一個配置類,和以前編寫的配置檔案一樣,也可以給容器中添加元件;
@Configuration
//将與配置檔案綁定好的某個類注入到容器中,使其生效
//進入這個HttpProperties檢視,将配置檔案中對應的值和HttpProperties綁定起來;
//并把HttpProperties加入到ioc容器中
@EnableConfigurationProperties(HttpProperties.class)
//Spring底層@Conditional注解
//根據不同的條件判斷,如果滿足指定的條件,整個配置類裡面的配置就會生效;
//這裡的意思就是判斷目前應用是否是web應用,如果是,目前配置類生效
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
//判斷系統中有沒有CharacterEncodingFilter這個類,如果有配置類才生效
@ConditionalOnClass(CharacterEncodingFilter.class)
//判斷配置檔案中是否存在某個配置:spring.http.encoding.enabled;
//matchIfMissing = true表明即使我們配置檔案中不配置pring.http.encoding.enabled=true,該配置類也是預設生效的;
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
//該類已經與配置檔案綁定了
private final HttpProperties.Encoding properties;
//建構該自動配置類時将與配置檔案綁定的配置類作為入參傳遞進去
public HttpEncodingAutoConfiguration(HttpProperties properties) {
this.properties = properties.getEncoding();
}
@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name()); //注入bean時使用配置類中屬性的值進行初始化,相當于将配置檔案中的值映射到了元件的某些屬性上
filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
return filter; //注入配置好的bean
}
}
一句話總結下自動配置類的工作過程 :
首先容器會根據目前不同的條件判斷,決定這個配置類是否生效!
一但這個配置類生效;這個配置類就會給容器中添加相應元件;
這些元件的屬性是從對應的properties類中擷取的,這些類裡面的每一個屬性又是和配置檔案綁定的;
所有在配置檔案中能配置的屬性都是在xxxxProperties類中封裝着,配置檔案可以配置什麼内容,可以參照該字首對應的屬性類中的屬性字段
//從配置檔案中擷取指定的值和bean的屬性進行綁定
@ConfigurationProperties(prefix = "spring.http")
public class HttpProperties {
// .....
2.2 SpringBoot自動配置使用總結
SpringBoot啟動會加載大量的自動配置類
我們首先可以看我們需要的功能有沒有在SpringBoot預設寫好的自動配置類當中;
我們再來看這個自動配置類中到底配置了哪些元件;(隻要我們要用的元件存在在其中,我們就不需要再手動配置了)
給容器中自動配置類添加元件的時候,會從properties類中擷取某些屬性。我們隻需要在配置檔案中指定這些屬性的值即可;
xxxxAutoConfigurartion:自動配置類;給容器中添加元件
xxxxProperties:封裝配置檔案中相關屬性;
了解完自動裝配的原理後,我們來關注一個細節問題,自動配置類必須在一定的條件下才能生效;@Conditional派生注解(Spring注解版原生的@Conditional作用)
作用:必須是@Conditional指定的條件成立,才給容器中添加元件,配置裡面的所有内容才生效;
三、自定義場景啟動器
現在我們已經了解了場景啟動器的概念以及其隐藏在背後的自動配置的原理,我們就可以自己來對SpringBoot進行功能拓展,定義我們自己的場景啟動器。
3.1 starter的命名規範
官方命名空間
字首:spring-boot-starter-
模式:spring-boot-starter-子產品名
舉例:spring-boot-starter-web、spring-boot-starter-jdbc
自定義命名空間
字尾:-spring-boot-starter
模式:子產品-spring-boot-starter
舉例:mybatis-spring-boot-starter
推薦一個 Spring Boot 基礎教程及實戰示例:
3.2 starter子產品整體結構
通過上邊的介紹,可以總結starter的整體實作邏輯主要由兩個基本部分組成:
xxxAutoConfiguration:自動配置類,對某個場景下需要使用到的一些元件進行自動注入,并利用xxxProperties類來進行元件相關配置
xxxProperties:某個場景下所有可配置屬性的內建,在配置檔案中配置可以進行屬性值的覆寫 按照SpringBoot官方的定義,Starer的作用就是依賴聚合,是以直接在starter内部去進行代碼實作是不符合規定的,starter應該隻起到依賴導入的作用,而具體的代碼實作應該去交給其他子產品來實作,然後在starter中去引用該子產品即可,是以整體的starter的構成應該如下圖所示:
可見starter子產品依賴了兩部分,一部分是一些常用依賴,另一部分就是對自動配置子產品的依賴,而xxxAutoConfiguration與xxxProperties的具體實作,都封裝在自動配置子產品中,starter實際是通過該子產品來對外提供相應的功能。
3.3 autoconfigure子產品開發
3.3.1 依賴引入
首先所有的自動配置子產品都要引入兩個jar包依賴:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<!-- 包含很多與自動配置相關的注解的定義,必須要引入 -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<!-- 非必須的,引入後可以在配置檔案中輸入我們自定義配置的時候有相應的提示,也可以通過其他.properties檔案為相關類進行屬性映射(SpringBoot預設使用application.yml)-->
<optional>true</optional>
</dependency>
<dependencies>
其他依賴的選擇根據項目需要進行添加即可
3.3.2 xxxAutoConfiguration的實作
autoconfigure子產品中最重要的就是自動配置類的編寫,它為我們實作元件的自動配置與自動注入。
在編寫自動配置類的時候,我們應該要考慮向容器中注入什麼元件,如何去配置它。