引言
|
?
一、注解解析
-
@SpringApplication
從啟動類@SpringApplication
注解入手,@SpringBootApplication
是一個組合注解,它是Spring Boot
框架中常用的一個主要注解之一。它結(jié)合了多個注解,簡化了Spring Boot
應用程序的配置。
@SpringBootApplication
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
?
@SpringBootApplication
?包含以下三個核心注解:
-
@SpringBootConfiguration
:這是Spring Boot
框架中的一個元注解,用于標識該類為Spring Boot
的配置類。配置類是用來定義Bean
和配置應用程序的類。 -
@EnableAutoConfiguration
:這個注解告訴Spring Boot
根據(jù)類路徑下的依賴和配置自動配置Spring
應用程序。它利用了Spring Boot
的自動配置特性,根據(jù)條件化配置的原理,自動配置所需的Bean
、組件和屬性。 -
@ComponentScan
:這個注解用于指定Spring Boot
掃描組件的基礎(chǔ)包。Spring Boot會掃描這個包及其子包,查找?guī)в凶⒔猓ɡ?code>@Controller、@Service
、@Repository
、@Component
等)的類,并將它們注冊為Spring
管理的Bean
。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration //標識為配置類
@EnableAutoConfiguration //開啟自動配置
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
...省略
}
EnableAutoConfiguration
?是自動裝配的核心,下面我們對該注解展開分析。
-
@EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
...省略
}
在@EnableAutoConfiguration
的源碼中,可以看到它使用@Import
注解引入了AutoConfigurationImportSelector
類。當Spring bean后置處理器掃描解析啟動類下所有包創(chuàng)建beanDefinition
時,AutoConfigurationImportSelector
會觸發(fā)自動裝配的加載過程。
-
@Import擴展點
@Import
是一個用于導入其他配置類的擴展點。通過使用@Import
注解,我們可以在一個配置類中引入其他的配置類,從而將它們的Bean定義和配置合并到當前配置中。
@Import
導入配置類分為兩種:
- 實現(xiàn)
ImportSelector
接口的類,執(zhí)行selectImports()
返回一個字符串數(shù)組,其中包含要導入的配置類的全限定名。 - 實現(xiàn)
ImportBeanDefinitionRegistrar
接口的類,執(zhí)行registerBeanDefinition()
可以動態(tài)地注冊Bean定義,從而實現(xiàn)更復雜的配置。
通過上述可知AutoConfigurationImportSelector
??實現(xiàn)ImportSelector
接口。該自動裝配核心類邏輯在接下的分析中展開說
二、spring boot 自動裝配原理分析
初始化SpringApplication
@SpringBootApplication
public class MyApp {
public static void main(String[] args) {
//第一步
SpringApplication.run(MyApp.class, args);
}
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
//第二步
return new SpringApplication(primarySources).run(args);
}
//第三步
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
//資源加載器
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
//設(shè)置啟動引導類
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//web應用類型:
// 1. NONE 非web應用程序
// 2. SERVLET web應用程序
// 3. REACTIVE 響應式web引用程序
//通過web應用類路徑選擇web應用類型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//Spring SPI機制獲取key為 ApplicationContextInitializer的類,并將它們作為應用程序上下文初始化器(ApplicationContextInitializer)注冊
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//Spring SPI機制獲取key為 ApplicationListener,并將它們作為應用程序事件監(jiān)聽器(ApplicationListener)注冊
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
這塊關(guān)注第一次調(diào)用Spring SPI機制的setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
Spring SPI機制
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
//Spring SPI機制加載 META-INF/spring.factories 文件以key,value形式的自動裝配類
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
通過?SpringFactoriesLoader.loadFactoryNames(type, classLoader)
?方法,從?META-INF/spring.factories
?文件中加載指定接口類型的實現(xiàn)類的名稱集合,并將它們保存在一個?Set
?中。
-
META-INF/spring.factories
: 通常是用于自動裝配的配置文件,其包含了需要自動裝配的類的全限定名。
一些八股文認為在
AutoConfigurationImportSelector
使用Spring SPI
加載META-INF/spring.factories
獲取自動裝配類 ,其實不然,Spring SPI
只加載一次META-INF/spring.factories
,以key-value的形式進行本地緩存,后續(xù)觸發(fā)自動裝配時,從本地緩存中獲取自動裝配類集合
Spring Boot啟動的核心邏輯
public ConfigurableApplicationContext run(String... args) {
.
.省略
.
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//初始化并配置應用程序的環(huán)境,包括加載配置文件、解析命令行參數(shù)、設(shè)置系統(tǒng)屬性等。
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
//打印Banner
Banner printedBanner = printBanner(environment);
//根據(jù)web類型創(chuàng)建ApplicationContext
context = createApplicationContext();
//SpringBootExceptionReporter用于報告Spring Boot應用程序啟動過程中的異常
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//準備ApplicationContext,包括設(shè)置環(huán)境、配置監(jiān)聽器、初始化Bean等操作。
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//這里會完成整個Spring IoC容器的初始化,包括解析Bean的定義,創(chuàng)建Bean實例,以及處理依賴注入等。
refreshContext(context);
.
.省略
.
return context;
}
上述代碼中,除了createApplicationContext()
、refreshContext(context)
,其他部分與自動裝配無關(guān)。在后續(xù)的文章中,會進一步介紹這部分內(nèi)容。
createApplicationContext()做了什么?
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
//根據(jù)webApplicationType枚舉類型,創(chuàng)建應用
switch (this.webApplicationType) {
case SERVLET: //SERVLET web應用程序
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE: //REACTIVE 響應式web引用程序
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default: //NONE 非web應用程序
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass",
ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
public AnnotationConfigServletWebServerApplicationContext() {
//用于讀取基于注解的Bean定義的類
this.reader = new AnnotatedBeanDefinitionReader(this);
//用于掃描類路徑中的組件,并將其注冊為Spring管理的Bean定義。
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
//注冊BeanFactory后置處理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
//注冊BeanFactory后置處理器
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
.
.省略
.
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
//自動裝配重點:創(chuàng)建BeanFactory后置處理器 ConfigurationClassPostProcessor,用于掃描解析啟動類當前包以及子包下的配置類
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
//注冊 ConfigurationClassPostProcessor
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
//創(chuàng)建BeanFactory后置處理器 CommonAnnotationBeanPostProcessor,處理依賴注入@Resource、WebServiceRef標注的字段以及方法
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
//注冊CommonAnnotationBeanPostProcessor
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
.
.省略
.
return beanDefs;
}
上述這段代碼整體來說非常簡單,根據(jù) web應用類型創(chuàng)建ApplicationContext
, 例如web應用類型為 SERVLET,創(chuàng)建AnnotationConfigServletWebServerApplicationContext
。通過AnnotationConfigServletWebServerApplicationContext
構(gòu)造方法創(chuàng)建?AnnotatedBeanDefinitionReader
以及ClassPathBeanDefinitionScanner
,我們需要注意的是AnnotatedBeanDefinitionReader
涉及BeanFactory
后置處理器注冊的內(nèi)容,可以看到這一步注冊了ConfigurationClassPostProcessor
-
AnnotatedBeanDefinitionReader
: 用于讀取基于注解的Bean定義的類 -
ClassPathBeanDefinitionScanner
: 用于掃描類路徑中的組件 -
ConfigurationClassPostProcessor
?:? ? 用于掃描解析啟動類當前包以及子包下的配置類
refreshContext(context)做了什么?
@Override
public void refresh() throws BeansException, IllegalStateException {
...省略
/**
* 共注冊了2個后置處理器
* ApplicationContextAwareProcessor,用于執(zhí)行xxxAware接口中的方法
* ApplicationListenerDetector,保證監(jiān)聽器被添加到容器中
*/
prepareBeanFactory(beanFactory);
try {
//為容器的某些子類指定特殊的BeanPost事件處理器
postProcessBeanFactory(beanFactory);
//觸發(fā)BeanFactory后置處理器
//定位注冊加載BeanDefinition, 能讓我們對容器中掃描出來的BeanDefinition做出修改以達到擴展的目的
invokeBeanFactoryPostProcessors(beanFactory);
//說白了就是beanFactory.addBeanPostProcessor(postProcessor);添加bean后置處理器
registerBeanPostProcessors(beanFactory);
初始化容器事件傳播器,添加事件傳播器到IOC容器
initApplicationEventMulticaster();
//啟動容器
onRefresh();
//為事件傳播器注冊事件監(jiān)聽器.
registerListeners();
//將解析的BeanDefinition注冊到IOC容器中
finishBeanFactoryInitialization(beanFactory);
//初始化容器的生命周期事件處理器,并發(fā)布容器的生命周期事
finishRefresh();
}
...省略
}
在refreshContext
方法中,完成了整個Spring IoC
容器的初始化,包括解析Bean
的定義、創(chuàng)建Bean
實例以及處理依賴注入等。我們主要關(guān)注invokeBeanFactoryPostProcessors(beanFactory)
對配置類進行定位解析注冊BeanDefinition
invokeBeanFactoryPostProcessors(beanFactory)做了什么?
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
//遍歷內(nèi)部所有BeanDefinitionRegistry后置處理器 (繼承 BeanFactoryPostProcessor),
//調(diào)用 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry 解析配置類成benaDefinition并注冊
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
//第二步:
在invokeBeanFactoryPostProcessors
方法中,會觸發(fā)所有BeanFactory
后置處理器的執(zhí)行,其中ConfigurationClassPostProcessor
后置處理器負責掃描解析啟動類當前包以及子包下的配置類,并將其注冊為Spring
管理的BeanDefinition
,接下來我們就看看它的源碼
ConfigurationClassPostProcessor源碼分析
//調(diào)用 ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
//獲取傳入的 BeanDefinitionRegistry 對象 registry 的哈希碼,作為標識
int registryId = System.identityHashCode(registry);
//通過檢查 registriesPostProcessed 集合和 factoriesPostProcessed 集合,防止了在同一個 BeanDefinitionRegistry 上重復執(zhí)行邏輯
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
//第三步
processConfigBeanDefinitions(registry);
}
//處理一些自定義的BeanDefinition
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
//存放加了注解@Configuration @Component @ComponentScan @Import @ImportResource的類
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
//判斷是否已經(jīng)處理
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
} else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
//存放加了注解@Configuration @Component @ComponentScan @Import @ImportResource的類
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
...省略
// 創(chuàng)建配置類解析器,構(gòu)造方法會創(chuàng)建ComponentScanAnnotationParser掃描器
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
//1.解析
parser.parse(candidates);
//驗證
parser.validate();
// 已經(jīng)解析過的配置類
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
// 移除已經(jīng)解析過的配置類,防止重復加載了配置類中的bd
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
// 2. 將所有ConfigurationClass解析成BeanDefinition進行 @Condition... 匹配,然后注冊到beanDefinition容器中
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
// 如果大于,說明容器中新增了一些BeanDefinition,那么需要重新判斷新增的bd是否是配置類,如果是配置類,需要再次解析
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
// 注冊ImportRegistry到容器中
// 當通過@Import注解導入一個全配置類A(被@Configuration注解修飾的類),A可以實現(xiàn)ImportAware接口
// 通過這個Aware可以感知到是哪個類導入的
if (sbr != null) {
if (!sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
//解析
public void parse(Set<BeanDefinitionHolder> configCandidates) {
this.deferredImportSelectors = new LinkedList<>();
// 在 new SpringApplication時候,會將 啟動類 生成為AnnotatedBeanDefinition,然后注入到beanDefinition容器中
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
//注解類解析方式
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
} else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
//普通類解析方式
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
} else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
} catch (BeanDefinitionStoreException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
//處理啟動類的自動裝配注解上@Import,對于 實現(xiàn)ImportSelector接口的執(zhí)行selectImport
processDeferredImportSelectors();
}
private void processDeferredImportSelectors() {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
if (deferredImports == null) {
return;
}
Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);
for (DeferredImportSelectorHolder deferredImport : deferredImports) {
ConfigurationClass configClass = deferredImport.getConfigurationClass();
try {
// 獲取啟動類上的所有@Import的實現(xiàn)ImportSelector類,執(zhí)行selectImports
// 自動裝配就在此處觸發(fā),獲取類處境
String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
// 處理selectImports返回的可導入自動裝配類
//1. 實現(xiàn)imporselect接口,則創(chuàng)建為實例調(diào)用selectImprot方法,然后遞歸調(diào)用處理import
//2. 實現(xiàn)importRegistry接口,則緩存到importBeanDefinitionRegistrars集合
//3. 非上述接口,則當做配置類處理。解析@PropertySources、@ComponentScans、@Import、@Bean
processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
} catch (BeanDefinitionStoreException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
}
}
上述代碼主要流程:
-
配置類解析器進行解析
- 注解方式解析
- 解析啟動類
@ComponentScans
注解信息獲取basePackages
、basePackageClasses
?,沒有則將啟動類包路徑 - 創(chuàng)建
ClassPathBeanDefinitionScanner
對當前包以及子包下所有后綴.class文件進行掃描解析@Component
、@Controller
、@Service
、@Repository
以及@Configura
配置類的@PropertySources
、@Import
、@Bean
生成ConfigurationClass
- 將
ConfigurationClass
與excludeFilters
進行排除過濾、Conditional
進行條件匹配
- 解析啟動類
- 處理啟動類上的
@Import
擴展點
- 注解方式解析
-
將所有
ConfigurationClass
解析成BeanDefinition
與?@ConditiOnXXX
?進行條件匹配,最后注冊到BeanDefinition
容器中
@bean 等價于 factory-method
@bean 所在的類 等價于 factory-bean
自動裝配核心邏輯 - AutoConfigurationImportSelector
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
//加載組件自動配置類元信息spring-autoconfigure-metadata.properties
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//獲取key為EnableAutoConfiuration對應的value集合
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
//自動裝配類去重
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
//根據(jù)maven導入的啟動器,過濾出需要導入的自動裝配類
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
}
上面這段代碼主要做了四件事
- 加載
spring-autoconfigure-metadata.properties
文件得到組件自動裝配類元信息 - 從
Spring SPI
?本地緩存中獲取key
為EnableAutoConfiuration
對應的自動裝配類集合 - 使用
LinkedHashSet
對自動裝配類做去重操作 - 將自動配置類與
spring-autoconfigure-metadata.properties
進行條件匹配過濾出需要導入的自動裝配類 (例如?@ConditionalOnClass
?) - 返回自動裝配類數(shù)組
通過本文前部分的注解分析已知AutoConfigurationImportSelector
實現(xiàn)ImportSelector
接口。當ConfigurationClassPostProcessor
后置處理器處理@Import
時,就會觸發(fā)自動裝配核心類AutoConfigurationImportSelector#selectImprot()
獲取Spring SPI
?本地緩存key
為EnableAutoConfiuration
的自動裝配類集合,然后去重過濾返回需要導入的自動裝配類數(shù)組。文章來源:http://www.zghlxwxcb.cn/news/detail-802925.html
三、小結(jié)
簡單的來說,Spring Boot的自動裝配原理主要依賴于Spring SPI
機制+@Import
擴展點+?ConfigurationClassPostProcessor
實現(xiàn)。ConfigurationClassPostProcessor
后置處理器會在掃描解析啟動類當前包以及子包下的配置類,并將其注冊為Spring管理的BeanDefinition
,從而實現(xiàn)自動裝配。而AutoConfigurationImportSelector
作為自動裝配核心類,在處理@Import邏輯中觸發(fā)自動裝配的過程,最終獲取需要導入的自動裝配類集合,實現(xiàn)Spring Boot的自動裝配功能。文章來源地址http://www.zghlxwxcb.cn/news/detail-802925.html
到了這里,關(guān)于Spring Boot源碼解析 - 自動裝配原理的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!