文章目錄
- 1. 未使用Spring Boot Starter前的情況
- 2. Spring Boot Starter簡介
- 2.1 什么是Spring Boot Starter(啟動器)
- 2.2 Starter 模塊整體結構
- 2.3 Spring 官方提供的 Starter 和 Starter 命名規范
- 3. 自定義Spring Boot Starter
- 3.1 根據 starter 命名規范創建一個 spring boot 專案
- 3.2 在 pom.xml 檔案中引入依賴
- 3.3 撰寫`ConfigInfo.java`、`ConfigService.java`、 `ConfigServiceImpl.java`
- 3.4 撰寫ConfigProperties.java
- 3.5 撰寫ConfigAutoConfiguration.java
- 3.6 撰寫spring.factories
- 3.7 發布自定義 starter
- 3.8 測驗自定義 starter
- 3.8.1 添加config-spring-boot-starter依賴
- 3.8.2 配置application.yml
- 3.8.3 撰寫 ConfigInfoController.java
- 3.8.4 啟動測驗
- 4. Spring Boot Starter原理
- 4.1 自動配置原理
- 4.1.1 自動配置類的獲取與注入
- 4.1.2 自動配置的程序
- 4.2 Spring Boot自動配置使用總結
企業級spring-boot案例系列文章上線了,涵蓋了大部分企業級的spring-boot使用場景,會不定期進行更新,企業級spring-boot案例原始碼地址:https://gitee.com/JourWon/spring-boot-example,歡迎各位大佬一起學習和指正
1. 未使用Spring Boot Starter前的情況
在沒有 starter 之前,假如我想要在 Spring 中使用 jpa,那我可能需要做以下操作:
- 在 Maven 中引入使用的資料庫的依賴(即 JDBC 的 jar)
- 引入 jpa 的依賴
- 在 xxx.xml 中配置一些屬性資訊
- 反復的除錯直到可以正常運行
需要注意的是,上面的操作在我們每次新建一個需要用到 jpa 的專案的時候都需要重復的做一次,
但在 Spring Boot 中,一切因為 Starter 變得簡單
- 在
pom檔案中引入spring-boot-starter-data-jpa - 在
.properties檔案中配置引數
通過上面兩個步驟,配置自動生效,具體生效的 bean 是 JpaRepositoriesAutoConfiguration,自動配置類的名字都有一個特點,叫做 xxxAutoConfiguration,
這就是使用 Spring 框架開發專案帶來的一些的問題:
- 依賴匯入問題: 每個專案都需要來單獨維護自己所依賴的jar包,在專案中使用到什么功能就需要引入什么樣的依賴,手動匯入依賴容易出錯,且無法統一集中管理
- 配置繁瑣: 在引入依賴之后需要做繁雜的配置,并且這些配置是每個專案來說都是必要的,例如web.xml配置(Listener配置、Filter配置、Servlet配置)、log4j配置、資料庫連接池配置等等,這些配置重復且繁雜,在不同的專案中需要進行多次重復開發,這在很大程度上降低了我們的開發效率
而在 Spring Boot 出現之后,它為我們提供了一個強大的功能來解決上述的兩個痛點,這就是 Spring Boot 的 starters(啟動器),
2. Spring Boot Starter簡介
2.1 什么是Spring Boot Starter(啟動器)
Spring Boot 通過將我們常用的功能抽取出來,做成的一系列啟動器,這些啟動器幫我們匯入了實作各個功能所需要依賴的全部組件,我們只需要在專案中引入這些 starters,需要的依賴就會全部被匯入進來,并且我們通過【約定大于配置】的方式,拋棄繁雜的配置,僅需要通過組態檔來進行少量的配置就可以使用相應的功能,
starter 的實作:雖然不同的 starter 實作起來各有差異,但是他們基本上都會使用到兩個相同的內容:ConfigurationProperties 和 AutoConfiguration,因為 Spring Boot 堅信 “約定大于配置” 這一理念,所以我們使用 ConfigurationProperties 來保存我們的配置,并且這些配置都可以有一個默認值,即在我們沒有主動覆寫原始配置的情況下,默認值就會生效,這在很多情況下是非常有用的,除此之外,starter 的 ConfigurationProperties 還使得所有的配置屬性被聚集到一個檔案中(一般在 resources 目錄下的 application.properties),這樣我們就告別了 Spring 專案中眾多的 XML 配置,
2.2 Starter 模塊整體結構
starter的整體實作邏輯主要由兩個基本部分組成:
xxxAutoConfiguration:自動配置類,對某個場景下需要使用到的一些組件進行自動注入,并利用xxxProperties類來進行組件相關配置
xxxProperties:某個場景下所有可配置屬性的集成,在組態檔中配置可以進行屬性值的覆寫,按照SpringBoot官方的定義,Starer的作用就是依賴聚合,因此直接在starter內部去進行代碼實作是不符合規定的,starter應該只起到依賴匯入的作用,而具體的代碼實作應該交給其他模塊來實作,然后在starter中去參考該模塊即可,因此整體的starter的構成應該如下圖所示:

可見starter模塊依賴了兩部分,一部分是一些常用依賴,另一部分就是對自動配置模塊的依賴,而xxxAutoConfiguration與xxxProperties的具體實作,都封裝在自動配置模塊中,starter實際是通過該模塊來對外提供相應的功能,
2.3 Spring 官方提供的 Starter 和 Starter 命名規范
SpringBoot 提供了非常多的 Starter,下面列出常用的幾個:
| 序號 | 名稱 | 功能 |
|---|---|---|
| 1 | spring-boot-starter-web | 支持 Web 開發,包括 Tomcat 和 spring-webmvc |
| 2 | spring-boot-starter-redis | 支持 Redis 鍵值存盤資料庫,包括 spring-redis |
| 3 | spring-boot-starter-test | 支持常規的測驗依賴,包括 JUnit、Hamcrest、Mockito 以及 spring-test 模塊 |
| 4 | spring-boot-starter-aop | 支持面向切面的編程即 AOP,包括 spring-aop 和 AspectJ |
| 5 | spring-boot-starter-data-elasticsearch | 支持 ElasticSearch 搜索和分析引擎,包括 spring-data-elasticsearch |
| 6 | spring-boot-starter-jdbc | 支持JDBC資料庫 |
| 7 | spring-boot-starter-data-jpa | 支持 JPA ,包括 spring-data-jpa、spring-orm、Hibernate |
可以看到這些 Starter 的名稱都是以 spring-boot-starter 為開頭,后面跟著具體的模塊名,所有官方的 Starter 遵循相似的命名模式,
根據約定,Spring Boot官方的starter命名要定義為spring-boot-starter-*,自定義或者說第三方的要命名為thirdpartyproject-spring-boot-starter
- 官方命名空間
- 前綴:spring-boot-starter-
- 模式:spring-boot-starter-模塊名
- 舉例:spring-boot-starter-web、spring-boot-starter-actuator、spring-boot-starter-jdbc
- 自定義命名空間
- 后綴:-spring-boot-starter
- 模式:模塊-spring-boot-starter
- 舉例:mybatis-spring-boot-starter
3. 自定義Spring Boot Starter
如果你想要自己創建一個 starter,那么基本上包含以下幾步
3.1 根據 starter 命名規范創建一個 spring boot 專案
創建一個名為config-spring-boot-starter的 spring boot 專案
3.2 在 pom.xml 檔案中引入依賴
<!-- 自動配置依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<!-- 將被@ConfigurationProperties注解的類的屬性注入到元資料 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- starter非必須依賴,使用到了可以添加 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
3.3 撰寫ConfigInfo.java、ConfigService.java、 ConfigServiceImpl.java
ConfigInfo 配置資訊類,用于封裝配置資訊,
@Data
@Builder
public class ConfigInfo implements Serializable {
private static final long serialVersionUID = -2878523532668902073L;
/**
* ID
*/
private String id;
/**
* IP地址
*/
private String ip;
}
ConfigService 示例業務介面,這里我們定義了一個configInfo介面,用于獲取配置資訊,
public interface ConfigService {
/**
* 獲取配置資訊
*
* @return {@link ConfigInfo}
*/
ConfigInfo configInfo();
}
ConfigServiceImpl 業務邏輯實作類,用于實作功能,
public class ConfigServiceImpl implements ConfigService {
/**
* ID
*/
private String id;
/**
* ip
*/
private String ip;
/**
* 建構式
*
* @param id ID
* @param ip IP
*/
public ConfigServiceImpl(String id, String ip) {
this.id = id;
this.ip = ip;
}
/**
* 獲取配置資訊
*
* @return {@link ConfigInfo}
*/
@Override
public ConfigInfo configInfo() {
return ConfigInfo.builder().id(this.id).ip(this.ip).build();
}
}
3.4 撰寫ConfigProperties.java
創建一個組態檔讀取類 ConfigurationProperties 用于保存配置資訊(如果你的專案不使用配置資訊則可以跳過這一步,不過這種情況非常少見)
@ConfigurationProperties注解使開發人員可以輕松地將整個檔案.properties和yml檔案映射到一個物件中,撰寫Properties,應使用唯一的名稱空間,不要使用Spring Boot的名稱空間(如server,management,spring等),所以應在所有配置鍵前面加上自己的名稱空間,如我們這里使用的是com.jourwon.config作為配置名稱空間,
@Data
@ConfigurationProperties(value = "com.jourwon.config")
public class ConfigProperties {
/**
* ID標識
*/
private String id;
/**
* IP地址
*/
private String ip;
}
3.5 撰寫ConfigAutoConfiguration.java
創建一個 AutoConfiguration,撰寫帶有@Configuration的配置類,并添加@EnableConfigurationProperties注解,@EnableConfigurationProperties作用是為了使@ConfigurationProperties注解的類生效,
@Slf4j
@Configuration
@EnableConfigurationProperties(value = ConfigProperties.class)
public class ConfigAutoConfiguration {
@Resource
private ConfigProperties properties;
/**
* 配置ExampleService
*
* @return {@link ConfigService}
*/
@Bean
@ConditionalOnMissingBean
public ConfigService configService() {
log.info("Config ConfigService Start...");
ConfigService service = new ConfigServiceImpl(properties.getId(), properties.getIp());
log.info("Config ConfigService End.");
return service;
}
}
3.6 撰寫spring.factories
在resources/META-INF/下創建spring.factories檔案,并且把上一步創建的AutoConfiguration類加入 spring.factories 組態檔中
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.jourwon.spring.boot.config.ConfigAutoConfiguration
3.7 發布自定義 starter
在自定義 starter 專案根目錄執行 mvn install 進行打包安裝
3.8 測驗自定義 starter
3.8.1 添加config-spring-boot-starter依賴
<properties>
<config-spring-boot-starter.version>1.0.0</config-spring-boot-starter.version>
</properties>
<dependencies>
<dependency>
<groupId>com.jourwon.spring.boot</groupId>
<artifactId>config-spring-boot-starter</artifactId>
<version>${config-spring-boot-starter.version}</version>
</dependency>
<!-- spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
</dependencies>
3.8.2 配置application.yml
IDE 提示
在使用官方starter的時候,我們可以發現IDE可以進行提示

在application.yml組態檔添加如下配置
# 自定義starter相關配置
com:
jourwon:
config:
id: 23145fdb-7427-42d1-ae29-a67f5be30d02
ip: 127.0.0.1
3.8.3 撰寫 ConfigInfoController.java
@RestController
public class ConfigInfoController {
@Resource
private ConfigService configService;
@GetMapping("/configInfo")
public String configInfo() {
return JSON.toJSONString(configService.configInfo());
}
}
3.8.4 啟動測驗
打開瀏覽器,輸入 http://127.0.0.1:8080/configInfo ,你將會看到我們配置的內容,

4. Spring Boot Starter原理
首先說說原理,我們知道使用一個公用的starter的時候,只需要將相應的依賴添加的Maven的組態檔當中即可,免去了自己需要參考很多依賴類,并且SpringBoot會自動進行類的自動配置,
在匯入的starter之后,SpringBoot主要幫我們完成了兩件事情:
- 相關組件的自動匯入
- 相關組件的自動配置
這兩件事情統一稱為SpringBoot的自動配置
那么 SpringBoot 是如何知道要實體化哪些類,并進行自動配置的呢? 下面簡單說一下,
首先,SpringBoot 在啟動時會去依賴的starter包中尋找 resources/META-INF/spring.factories檔案,然后根據檔案中配置的Jar包去掃描專案所依賴的Jar包,這類似于 Java 的 SPI 機制,
第二步,根據 spring.factories配置加載AutoConfigure類,
最后,根據 @Conditional注解的條件,進行自動配置并將Bean注入Spring Context 背景關系當中,
我們也可以使用@ImportAutoConfiguration({MyServiceAutoConfiguration.class}) 指定自動配置哪些類,
4.1 自動配置原理
4.1.1 自動配置類的獲取與注入
我們從主程式入口來探索一下整個程序的原理:
//標注這個類是一個springboot的應用
@SpringBootApplication
public class CommunityApplication {
public static void main(String[] args) {
//將springboot應用啟動
SpringApplication.run(CommunityApplication.class, args);
}
}
@SpringBootApplication注解內部結構如下圖所示:

AutoConfigurationImportSelector :重點看該類中重寫的selectImports方法,看下它回傳的字串陣列是如何得來的:

我們可以去到上邊提到的spring.factories檔案中去看一下,找到spring官方提供的spring-boot-autoconfigure包,在其下去找一下該檔案:

可以看到這個就是SpringBoot官方為我們提供的所有自動配置類的候選串列,我們可以在其中找到一個我們比較熟悉的自動配置類去看一下它內部的實作:
可以看到這些一個個的都是JavaConfig配置類,而且都通過@Bean注解向容器中注入了一些Bean

結論:
- SpringBoot在啟動的時候從類路徑下的
META-INF/spring.factories中獲取EnableAutoConfiguration指定的所有自動配置類的全限定類名 - 將這些自動配置類匯入容器,自動配置類就生效,幫我們進行自動配置作業;
- 整個J2EE的整體解決方案和自動配置都在
spring-boot-autoconfigure的jar包中; - 它會給容器中匯入非常多的自動配置類 (xxxAutoConfiguration), 就是給容器中匯入這個場景需要的所有組件,并配置好這些組件 ;
- 有了自動配置類,免去了我們手動撰寫配置注入功能組件等的作業;
4.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表明即使我們組態檔中不配置spring.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();
//注入bean時使用配置類中屬性的值進行初始化,相當于將組態檔中的值映射到了組件的某些屬性上
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
//注入配置好的bean
return filter;
}
}
一句話總結下自動配置類的作業程序 :
- 首先容器會根據當前不同的條件判斷,決定這個配置類是否生效!
- 一但這個配置類生效;這個配置類就會給容器中添加相應組件;
- 這些組件的屬性是從對應的properties類中獲取的,這些類里面的每一個屬性又是和組態檔系結的;
- 所有在組態檔中能配置的屬性都是在xxxxProperties類中封裝著,組態檔可以配置什么內容,可以參照該前綴對應的屬性類中的屬性欄位
//從組態檔中獲取指定的值和bean的屬性進行系結
@ConfigurationProperties(prefix = "spring.http")
public class HttpProperties {
// .....
}
4.2 Spring Boot自動配置使用總結
-
SpringBoot啟動會加載大量的自動配置類
-
我們首先可以看我們需要的功能有沒有在SpringBoot默認寫好的自動配置類當中;
-
我們再來看這個自動配置類中到底配置了哪些組件;(只要我們要用的組件存在在其中,我們就不需要再手動配置了)
-
給容器中自動配置類添加組件的時候,會從properties類中獲取某些屬性,我們只需要在組態檔中指定這些屬性的值即可;
-
xxxxAutoConfigurartion:自動配置類;給容器中添加組件xxxxProperties:封裝組態檔中相關屬性;
了解完自動裝配的原理后,我們來關注一個細節問題,自動配置類必須在一定的條件下才能生效;@Conditional派生注解(Spring注解版原生的@Conditional作用)
作用:必須是@Conditional指定的條件成立,才給容器中添加組件,配置里面的所有內容才生效;
| 序號 | @Conditional擴展注解 | 作用(判斷是否滿足當前條件) |
|---|---|---|
| 1 | @ConditionalOnWebApplication | 當前專案是Web專案的條件下 |
| 2 | @ConditionalOnNotWebApplication | 當前專案不是Web專案的條件下 |
| 3 | @ConditionalOnResource | 類路徑下是否有指定的資源 |
| 4 | @ConditionalOnExpression | 基于SpEL運算式作為判斷條件 |
| 5 | @ConditionalOnMissingBean | 當容器中沒有指定Bean的情況下 |
| 6 | @ConditionalOnBean | 當容器中有指定的Bean的條件下 |
| 7 | @ConditionalOnSingleCandidate | 當指定的Bean在容器中只有一個,或者在有多個Bean的情況下,用來指定首選的Bean |
| 8 | @ConditionalOnJava | 基于JVM版本作為判斷條件 |
| 9 | @ConditionalOnMissingClass | 當類路徑下沒有指定的類的條件下 |
| 10 | @ConditionalOnClass | 當類路徑下有指定的類的條件下 |
| 11 | @ConditionalOnProperty | 指定的屬性是否有指定的值 |
那么多的自動配置類,必須在一定的條件下才能生效;也就是說,我們加載了這么多的配置類,但不是所有的都生效了,
我們怎么知道哪些自動配置類生效?
我們可以通過啟用 debug=true屬性;來讓控制臺列印自動配置報告,這樣我們就可以很方便的知道哪些自動配置類生效;
#在組態檔中開啟springboot的除錯類
debug=true
Positive matches:(自動配置類啟用的:正匹配)
Positive matches:
-----------------
AopAutoConfiguration matched:
- @ConditionalOnClass found required classes 'org.springframework.context.annotation.EnableAspectJAutoProxy', 'org.aspectj.lang.annotation.Aspect', 'org.aspectj.lang.reflect.Advice', 'org.aspectj.weaver.AnnotatedElement' (OnClassCondition)
- @ConditionalOnProperty (spring.aop.auto=true) matched (OnPropertyCondition)
AopAutoConfiguration.CglibAutoProxyConfiguration matched:
- @ConditionalOnProperty (spring.aop.proxy-target-class=true) matched (OnPropertyCondition)
AuditAutoConfiguration#auditListener matched:
- @ConditionalOnMissingBean (types: org.springframework.boot.actuate.audit.listener.AbstractAuditListener; SearchStrategy: all) did not find any beans (OnBeanCondition)
AuditAutoConfiguration#authenticationAuditListener matched:
- @ConditionalOnClass found required class 'org.springframework.security.authentication.event.AbstractAuthenticationEvent' (OnClassCondition)
- @ConditionalOnMissingBean (types: org.springframework.boot.actuate.security.AbstractAuthenticationAuditListener; SearchStrategy: all) did not find any beans (OnBeanCondition)
Negative matches:(沒有啟動,沒有匹配成功的自動配置類:負匹配)
Negative matches:
-----------------
ActiveMQAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition)
AopAutoConfiguration.JdkDynamicAutoProxyConfiguration:
Did not match:
- @ConditionalOnProperty (spring.aop.proxy-target-class=false) did not find property 'proxy-target-class' (OnPropertyCondition)
AppOpticsMetricsExportAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'io.micrometer.appoptics.AppOpticsMeterRegistry' (OnClassCondition)
ArtemisAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition)
Exclusions、Unconditional classes(排除的、沒有限定條件的自動配置類):
Exclusions:
-----------
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
Unconditional classes:
----------------------
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration
org.springframework.boot.actuate.autoconfigure.endpoint.jmx.JmxEndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.info.InfoContributorAutoConfiguration
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/402719.html
標籤:java
