@EnableAutoConfiguration用于类或接口上,在spring boot中注解位于@SpringBootApplication注解上
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
……
}
当spring boot扫描到@EnableAutoConfiguration注解时则会将spring-boot-autoconfigure.jar/META-INF/spring.factories文件中org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的value里的所有xxxConfiguration类加载到IOC容器中。而xxxAutoConfiguration类一般都会有@ConditionalOnxxx注解,通过这些条件注解来判断是否真正的创建xxxConfiguration对象。spring boot的各种spring-boot-starter-xxx.jar也正是居于此注解来达到自动装配的目的。
@ConditionalOnxxx常见注解如下:
@ConditionalOnClass | classpath中存在该类时起效 |
@ConditionalOnMissingClass | classpath中不存在该类时起效 |
@ConditionalOnBean | DI容器中存在该类型Bean时起效 |
@ConditionalOnMissingBean | DI容器中不存在该类型Bean时起效 |
@ConditionalOnSingleCandidate | DI容器中该类型Bean只有一个或@Primary的只有一个时起效 |
@ConditionalOnExpression | SpEL表达式结果为true时 |
@ConditionalOnProperty | 参数设置或者值一致时起效 |
@ConditionalOnResource | 指定的文件存在时起效 |
@ConditionalOnJndi | 指定的Java版本存在时起效 |
@ConditionalOnWebApplication | Web应用环境下起效 |
@ConditionalOnNotWebApplication | 非Web应用环境下起效 |
通过《spring boot自动装配原理之@ComponentScan详解》一文我们知道spring boot自动装配的过程都是在ConfigurationClassPostProcessor这个BeanFactoryPostProcessor类中完成的。
核心流程如下:
public class ConfigurationClassPostProcessor {
…………
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set candidates = new LinkedHashSet<>(configCandidates);
Set alreadyParsed = new HashSet<>(configCandidates.size());
do {
//1、该方法执行完后会将这pring-boot-autoconfigure.jar/META-INF/spring.factories文件
//中org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的value值全部封装
//成ConfigurationClass对象存在parser对象的configurationClasses属性中。
parser.parse(candidates);
parser.validate();
//2、取出ConfigurationClass对象
configClasses.removeAll(alreadyParsed);
Set configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
// 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());
}
//3、将ConfigurationClass转换成ConfigurationClassBeanDefinition并注册到beanFactory中,
//以供后面创建具体的对象,该方法也很复杂,本文不深入研究
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
…………
}
下面是重点过程方法的拆分,断点走向:
ConfigurationClassPostProcessor.parse(……) --> this.deferredImportSelectorHandler.process(……) --> AutoConfigurationImportSelector.getCandidateConfigurations(……) --> SpringFactoriesLoader.loadFactoryNames(……) --> ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(……)
断点进入parse方法:
public void parse(Set configCandidates) {
……
this.deferredImportSelectorHandler.process();
}
进入 this.deferredImportSelectorHandler.process();断点一直跟踪到AutoConfigurationImportSelector的下面方法
protected AutoConfigurationEntry getAutoConfigurationEntry(
AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//这个列表对应pring-boot-autoconfigure.jar/META-INF/spring.factories文件中
//org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的value值
List configurations = getCandidateConfigurations(annotationMetadata,
attributes);
configurations = removeDuplicates(configurations);
Set exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
……
protected List getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
//加载属性文件中xxxAutoConfiguration配置
List configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
……
return configurations;
}
this.reader.loadBeanDefinitions(configClasses);方法执行完成后的截图如下:
当所有xxxConfiguration类转换成BeanDefinition对象并注册到DefaultListableBeanFactory后,后面就可以创建具体的bean对象了。