SpringBoot自動裝配原理 Created time: May 15, 2022 6:36 PM Done: Doing Last edited time: May 25, 2022 6:13 PM Tags: Spring, 後端, 總結 0 關於自動配置 pom.xml spring-bo ...
SpringBoot自動裝配原理
Created time: May 15, 2022 6:36 PM
Done: Doing
Last edited time: May 25, 2022 6:13 PM
Tags: Spring, 後端, 總結
0 關於自動配置
pom.xml
- spring-boot-dependencies:核心依賴在父工程中
- 在寫或者引入一些springboot依賴時,不需要指定版本,因為有這些版本倉庫。
啟動器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
- 啟動器,SpringBoot的啟動場景
- spring-boot-starter-web 自動導入web環境所有的依賴
- springboot會將所有的功能場景變成一個一個啟動器
主程式
//標註這個類是一個springboot的應用
@SpringBootApplication
public class Springboot01HelloworldApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot01HelloworldApplication.class, args);
}
}
1 SpringBoot四大核心
- 四大核心
EnableAutoConfiguration
自動裝配Starter
組件,開箱即用Actutor
監控- SpringBoot Cli為SpringCloud提供SpringBoot命令行功能
1.1 註解
在瞭解Spring註解之前先瞭解一些相關註解的知識。
//標註這個類是一個springboot的應用
@SpringBootApplication
//SpringBoot的配置
@SpringBootConfiguration
@Configuration //Spring配置類
@Component//本質還是一個Spring組件
//自動配置
@EnableAutoConfiguration
@AutoConfigurationPackage//自動配置包
@Import(AutoConfigurationPackages.Registrar.class)//導入選擇器包註冊
@Import(AutoConfigurationImportSelector.class)//自動配置導入選擇(自動導入包的核心)
//獲取所有的配置
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
//getCandidateConfigurations獲取所有的候選配置**
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(**getSpringFactoriesLoaderFactoryClass**(),
getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
//EnableAutoConfiguration註解被SpringBootApplication繼承
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
META-INF/spring.factories自動配置的核心文件
//所有的資源載入到類中
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
結論
SpringBoot所有自動配置都是在啟動的時候掃描並載入:spring.factories所有的自動配置類都在這裡面,但不一定生效,要判斷條件是否成立,只要導入對應的start,就有對應的啟動器了,有了啟動器,自動裝配就會生效,然後就配置成功。
2 Enable註解作用
EnableAutoConfiguration
自動裝配相關的Eable註解.
開啟相關支持,如
EnableScheduling
,開啟計劃任務支持EnableAutoConfiguration
,開啟自動裝配支持
在EnableAutoConfiguration.java
中涉及到Enable開頭的註解都會有一個@Import
的註解
3 SpringBoot中的自動裝配原理
自動裝配作為Starter的基礎,也是SpringBoot的核心
SpringBoot的自動裝配是基於EnableAutoConfiguration
實現的,先瞭解一下傳統意義的自動裝配方式。
首先需要瞭解一些前置關於註解的知識。
3.1 Configuration註解
Spring3以後,支持兩種配置bean的方式,一種xml文件方式和JavaConfig。
JavaConfig方式
Configuration
註解是JavaConfig形式基於Spring IOC容器配置類使用的一種註解。在啟動類裡邊標註@Configuration
也表示它是一個IOC容器的配置類。
public class DemoClass {
public void say(){
System.out.println("sya hello ... ");
}
}
@Configuration
@Import(UserClass.class)
public class DemoConfiguration {
@Bean
public DemoClass getDemoClass(){
return new DemoClass();
}
}
public class DemoConfigurationMain {
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(DemoConfiguration.class);
DemoClass bean = ac.getBean(DemoClass.class);
bean.say();
}
}
3.2 Configuration本質
Configuration註解本質就是一個Component註解,會被AnnotationConfigApplicationContext
載入,而AnnotationConfigApplicationContext
是ApplicationContext
的具體實現,會根據配置註解啟動應用上下文。所以在Main中通過AnnotationConfigApplicationContext
載入JavaConfig後,可以得到IOC容器中Bean的實例。
@Configuration //也會被Spring容器托管,註冊到容器中,因為本身就是一個@Component
@ComponentScan("com.kuang.pojo")
@Import(MyConfig2.class)
public class MyConfig {
//註冊一個Bean相當於之前寫的一個Bean標簽
//這個方法的名字就相當於Bean標簽中的id屬性
//這個方法的返回值,就相當於Bean標簽中的class屬性
@Bean
public User getUser(){
return new User(); //返回要註入到Bean的對象
}
}
public class MyTest {
public static void main(String[] args) {
//如果完全使用了配置類方式去做,只能通過AnnotationConfigApplicationContext來獲取容器,通過配置類的class對象載入
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
User getUser = (User) context.getBean("getUser");
System.out.println(getUser.getName());
}
}
@Component
public class User {
private String name;
public String getName() {
return name;
}
@Value("xxx")
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
3.3 ComponentScan註解
相當於xml配置文件中的
context:component-scan
,主要作用是掃描指定路徑下標識了需要裝配的類,自動裝配到IOC容器中
@Configuration //也會被Spring容器托管,註冊到容器中,因為本身就是一個@Component
@ComponentScan("com.kuang.pojo")
@Import(MyConfig2.class)
public class MyConfig {
//註冊一個Bean相當於之前寫的一個Bean標簽
//這個方法的名字就相當於Bean標簽中的id屬性
//這個方法的返回值,就相當於Bean標簽中的class屬性
@Bean
public User getUser(){
return new User(); //返回要註入到Bean的對象
}
}
3.4 Import註解
等同於xml形式下的<import resource/>
註解,將多個分開的容器合併在一個容器中。
方式一:@Import,直接
@Import(MyConfig2.class)
方式二:ImportSelector,動態載入實現
ImportSelector
介面
方式三:ImportBeanDefinitionRegistrar方式,實現
ImportBeanDefinitionRegistrar
介面
3.5 深入EnableAutoConfiguration原理
EnableAutoConfiguration
通過@Import(AutoConfigurationImportSelector.class)
導入第三方的提供的Bean配置類AutoConfigurationImportSelector
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
try {
// 載入META-INF/spring-autoconfigure-metadata.properties 下的元數據信息
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
// 獲取候選載入的配置信息 META-INF/spring.factories
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
// 去掉重覆的配置信息
configurations = this.removeDuplicates(configurations);
// 排序
configurations = this.sort(configurations, autoConfigurationMetadata);
// 獲取 註解中配置的 exclusion 信息
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
// 檢查
this.checkExcludedClasses(configurations, exclusions);
// 移除需要排除的信息
configurations.removeAll(exclusions);
// 過濾,檢查候選配置類上的註解@ConditionalOnClass,如果要求的類不存在,則這個候選類會被過濾不被載入
configurations = this.filter(configurations, autoConfigurationMetadata);
// 廣播事件
this.fireAutoConfigurationImportEvents(configurations, exclusions);
// 返回要被載入的類數組
return (String[])configurations.toArray(new String[configurations.size()]);
} catch (IOException var6) {
throw new IllegalStateException(var6);
}
}
}
EnableAutoConfiguration
會幫助SpringBoot應用將所有符合@Configuration
配置都載入到當前SpringBoot創建的IOC容器,這裡面藉助了Spring框架提供的一個工具類SpringFactoriesLoader
的支持。以及用到了Spring提供的條件註解@Conditional
,選擇性的針對需要載入的bean進行條件過濾。
3.6 關於條件過濾
分析
AutoConfigurationImportSelector
的源碼時,會先掃描spring-autoconfiguration-metadata.properties
文件,最後在掃描spring.factories
對應的類時,會結合前面的元數據進行過濾,為什麼要過濾呢? 原因是很多的@Configuration
其實是依托於其他的框架來載入的,如果當前的classpath
環境下沒有相關聯的依賴,則意味著這些類沒必要進行載入,所以,通過這種條件過濾可以有效的減少@configuration
類的數量從而降低SpringBoot
的啟動時間。
4 總結
SpringBoot自動裝配實現是從classpath中搜尋spring.factory自動裝配的核心文件,將包下對應的org.springframework.boot.autoconfigure的配置項通過反射實例化為對應標註的@Configuration的JavaConfig形式的IOC容器配置類,將然後彙總為實例載入至IOC容器中。
備註:思路還是不太清晰,後續還需再整理一遍深入理解。