SpringBoot自動配置原理
前言
後面還會講到SpringBoot自動配置原理,會主要講解@EnableAutoConfiguratuon註解幫助我們做了什麼事情,是如何自動把自動配置類掃描到容器中的,建議看完這篇後,兩篇配合使用,傳送門
package com.staticzz.springboot_quick;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
**@SpringBootApplication註解為核心註解
**
**/
@SpringBootApplication
public class SpringbootQuickApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootQuickApplication.class, args);
}
}
SpringBootApplication註解作用
@SpringBootApplication 標註在某一個類上,就說明這個類為SpringBoot應用的主配置類,SpringBoot就應該執行這個類的main方法來啟動Springboot應用
以前我們開發一個SSM專案,需要利用配置檔案進行相關配置,而SpingBoot利用了配置類進行自動配置,
這裡配置類等同於配置檔案,SpringBoot並且開啟了自動配置,以前我們需要手動配置的東西
這裡SpringBoot幫我們進行了自動配置
PS: 自動配置原理也是SpringBoot的精髓所在
package com.staticzz.springboot_quick;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
@SpringBootApplication註解標註在某一個類上,
就說明這個類為SpringBoot應用的主程式類
SpringBoot就應該執行這個類的main方法來啟動Springboot應用
**/
@SpringBootApplication
public class SpringbootQuickApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootQuickApplication.class, args);
}
}
那@SpringBootApplication 這個註解與自動配置又有什麼關係呢?
接下來我們Ctrl+左鍵,進入到這個註解中來檢視 @SpringBootApplication 這個註解裡到底配置了什麼?我們先來進入到@SpringBootApplication這個註解中,看看它底層呼叫了什麼註解
動圖演示:
我們觀察到 @SpringBootApplication註解 繼承了 @SpringBootConfiguration註解 ,而 @SpringBootConfiguration註解 又繼承了Spring底層的註解 @Configuration註解 , 凡是標註該註解的類都是配置類
那現在也只是知道了 @SpringBootApplication註解 一層一層的實現了Spring底層的 @Configuration註解 ,被標註後稱為配置類!那說了這篇文章講的是SpringBoot的自動配置?配置有了,自動呢?
我沒有騙人哦!確實是有自動配置的!而且SpringBoot也確確實實幫我們做了自動配置
先上一張動態演示圖,瞧瞧
第一步 ctrl+右鍵 進入了 @EnableAutoConfiguration 這個註解
@SuppressWarnings("deprecation")
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
/**
**這個註解為自動導包的註解
**/
@AutoConfigurationPackage
/**
**這個為開啟自動配置選擇器的註解
**/
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
String[] excludeName() default {};
}
有沒有發現我在這動態演示中,重點高亮了兩個註解
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
這兩個註解分別是什麼意思 廢話不多說 下面看!
@AutoConfigurationPackage 自動掃描包
@Import(EnableAutoConfigurationImportSelector.class) 匯入自動配置類選擇器元件
來看原始碼分析
@AutoConfigurationPackage
原始碼展示:
/**
* {@link ImportBeanDefinitionRegistrar} to store the base package from the importing
* configuration.
*/
@Order(Ordered.HIGHEST_PRECEDENCE)
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
//這個方法為SpringBoot幫助我們自動掃描包獲取獲取包名並進行註冊
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
register(registry, new PackageImport(metadata).getPackageName());
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.<Object>singleton(new PackageImport(metadata));
}
}
動態展示 自動掃描包
注意觀察動圖中我高亮的部分
結論:SpringBoot在啟動時,會自動掃描主程式類所在的包下的所有子包
來看原始碼分析
@Import(EnableAutoConfigurationImportSelector.class)
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
try {
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
//獲取到註解後設資料
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//獲取到配置類封裝為一個list資料
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
configurations = removeDuplicates(configurations);
configurations = sort(configurations, autoConfigurationMetadata);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
//返回給容器
return configurations.toArray(new String[configurations.size()]);
}
catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
@Import(EnableAutoConfigurationImportSelector.class) 這個註解的作用選擇自動配置類並掃描進容器中,
動態展示 匯入自動配置類選擇器元件