自動配置原理:
先總結下結論:
自動配置的原理大致是Springboot在啟動時通過spring.factories中的xxxAutoConfiguration找到xxxProperties類進行
默認自動配置(xxxAutoConfiguration類中有很多@Conditional的派生類作用是:當條件不成立時,自動配置會失敗),由於xxxProperties類中有@ConfigurationProperties注解會與application.yml配置文件綁定,因此我們可以在application.yml中覆蓋掉某些默認配置!
分析自動配置原理:
通過依次點開@SpringBootApplication->@EnableAutoConfiguration->AutoConfigurationImportSelector.class->getAutoConfigurationEntry方法->getCandidateConfigurations方法->loadFactoryNames方法->loadSpringFactories方法
->找到FACTORIES_RESOURCE_LOCATION變量:"META-INF/spring.factories";
我們找到了spring-boot-autoconfigure-2.5.2下的spring.factories文件,如下圖所示:
我們以HttpEncodingAutoConfiguration(Http編碼自動配置)為例解釋自動配置原理;
//表示這是一個配置類,和以前編寫的配置文件一樣,也可以給容器中添加組件;
@Configuration
//啟動指定類的ConfigurationProperties功能;
//進入這個HttpProperties查看,將配置文件中對應的值和HttpProperties綁定起來;
//並把HttpProperties加入到ioc容器中
@EnableConfigurationProperties({HttpProperties.class})
//Spring底層@Conditional注解
//根據不同的條件判斷,如果滿足指定的條件,整個配置類里面的配置就會生效;
//這里的意思就是判斷當前應用是否是web應用,如果是,當前配置類生效
@ConditionalOnWebApplication(
type = Type.SERVLET
)
//判斷當前項目有沒有這個類CharacterEncodingFilter;SpringMVC中進行亂碼解決的過濾器;
@ConditionalOnClass({CharacterEncodingFilter.class})
//判斷配置文件中是否存在某個配置:spring.http.encoding.enabled;
//如果不存在,判斷也是成立的
//即使我們配置文件中不配置pring.http.encoding.enabled=true,也是默認生效的;
@ConditionalOnProperty(
prefix = "spring.http.encoding",
value = {"enabled"},
matchIfMissing = true
)
public class HttpEncodingAutoConfiguration {
//他已經和SpringBoot的配置文件映射了
private final Encoding properties;
//只有一個有參構造器的情況下,參數的值就會從容器中拿
public HttpEncodingAutoConfiguration(HttpProperties properties) {
this.properties = properties.getEncoding();
}
//給容器中添加一個組件,這個組件的某些值需要從properties中獲取
@Bean
@ConditionalOnMissingBean //判斷容器沒有這個組件?
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));
return filter;
}
//。。。。。。。
}
一句話總結 :根據當前不同的條件判斷,決定這個配置類是否生效!
- 一但這個配置類生效;這個配置類就會給容器中添加各種組件;
- 這些組件的屬性是從對應的properties類中獲取的,這些類里面的每一個屬性又是和配置文件綁定的;
- 所有在配置文件中能配置的屬性都是在xxxxProperties類中封裝着;
- 配置文件能配置什么就可以參照某個功能對應的這個屬性類
//從配置文件中獲取指定的值和bean的屬性進行綁定
@ConfigurationProperties(prefix = "spring.http")
public class HttpProperties {
// .....
}
我們去配置文件里面試試前綴,看提示!
這就是自動裝配的原理!
總結:
1、SpringBoot啟動會加載大量的自動配置類
2、我們看我們需要的功能有沒有在SpringBoot默認寫好的自動配置類當中;
3、我們再來看這個自動配置類中到底配置了哪些組件;(只要我們要用的組件存在在其中,我們就不需要再手動配置了)
4、給容器中自動配置類添加組件的時候,會從properties類中獲取某些屬性。我們只需要在配置文件中指定這些屬性的值即可;
xxxxAutoConfigurartion:自動配置類;給容器中添加組件
xxxxProperties:封裝配置文件中相關屬性;
了解:@Conditional
了解完自動裝配的原理后,我們來關注一個細節問題,自動配置類必須在一定的條件下才能生效;
@Conditional派生注解(Spring注解版原生的@Conditional作用)
作用:必須是@Conditional指定的條件成立,才給容器中添加組件,配置配里面的所有內容才生效;
那么多的自動配置類,必須在一定的條件下才能生效;也就是說,我們加載了這么多的配置類,但不是所有的都生效了。
我們怎么知道哪些自動配置類生效?
我們可以通過在application.yaml/properties中啟用 debug=true屬性;來讓控制台打印自動配置報告,這樣我們就可以很方便的知道哪些自動配置類生效;
#開啟springboot的調試類
debug=true
Positive matches:(自動配置類啟用的:正匹配)
Negative matches:(沒有啟動,沒有匹配成功的自動配置類:負匹配)
Unconditional classes: (沒有條件的類)
自定義starter
我們分析完畢了源碼以及自動裝配的過程,我們可以嘗試自定義一個啟動器來玩玩!
說明:
啟動器模塊是一個 空 jar 文件,僅提供輔助性依賴管理,這些依賴可能用於自動裝配或者其他類庫;
命名歸約:
官方命名:
- 前綴:spring-boot-starter-xxx
- 比如:spring-boot-starter-web....
自定義命名:
- xxx-spring-boot-starter
- 比如:mybatis-spring-boot-starter
編寫啟動器
1、在IDEA中新建一個空項目 spring-boot-starter-diy
2、新建一個普通Maven模塊:kuang-spring-boot-starter
3、新建一個Springboot模塊:kuang-spring-boot-starter-autoconfigure
4、在我們的 starter 中 導入 autoconfigure 的依賴!
5、將 autoconfigure 項目下多余的文件都刪掉,Pom中只留下一個 starter,這是所有的啟動器基本配置!
6、首先在autoconfigure 項目中編寫一個自己的服務HelloService :
package com.kuang;
public class HelloService {
HelloProperties helloProperties;
public HelloProperties getHelloProperties() {
return helloProperties;
}
public void setHelloProperties(HelloProperties helloProperties) {
this.helloProperties = helloProperties;
}
public String sayHello(String name){
return helloProperties.getPrefix() + name + helloProperties.getSuffix();
}
}
7、再編寫一個HelloProperties 配置類
package com.kuang;
import org.springframework.boot.context.properties.ConfigurationProperties;
// 前綴 kuang.hello
@ConfigurationProperties(prefix = "kuang.hello")
public class HelloProperties {
private String prefix;
private String suffix;
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getSuffix() {
return suffix;
}
public void setSuffix(String suffix) {
this.suffix = suffix;
}
}
8、最后編寫我們的自動配置類HelloServiceAutoConfiguration:
package com.kuang;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConditionalOnWebApplication //web應用生效
@EnableConfigurationProperties(HelloProperties.class)
public class HelloServiceAutoConfiguration {
@Autowired
HelloProperties helloProperties;
@Bean
public HelloService helloService(){
HelloService service = new HelloService();
service.setHelloProperties(helloProperties);
return service;
}
}
9、最后在autoconfigure 項目中的resources目錄下編寫一個自己的 META-INF\spring.factories:
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.kuang.HelloServiceAutoConfiguration
10、編寫完成后,可以安裝到maven倉庫中!
總結:
個人總結來說:自定義一個starter需要起一個空的項目,然后再里面新建一個普通maven項目模塊和一個springboot項目模塊,maven項目的pom中國要引入springboot項目依賴,而在springboot項目里要寫xxxAutoConfiguration類、xxxProperties類以及自己要對外提供的服務,最后別忘了在resources目錄下的META-INF/spring.factories中寫上想對應的xxxAutoConfiguration就行!
新建一個項目測試我們自己寫的啟動器
1、新建一個SpringBoot 項目
2、導入我們自己寫的啟動器
<dependency>
<groupId>com.kuang</groupId>
<artifactId>kuang-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
3、編寫一個 HelloController 進行測試我們自己的寫的接口!
package com.kuang.testautocongure;
import com.kuang.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@Autowired
HelloService helloService;
@RequestMapping("/hello")
public String hello(){
return helloService.sayHello("zxc");
}
}
4、編寫配置文件 application.properties
kuang.hello.prefix="ppp"
kuang.hello.suffix="sss"
5.啟動項目進行測試,結果成功!
這就是自定義starter!
本項目代碼在碼雲的spring-boot-starter-diy項目和testAutoCongure項目中,之后會給出碼雲地址!