总结:
1、Spring Contex 和 Bean的解析和注册(@Configuration和@Import)
2、SpringFacotoriesLoader
3、@Conditional机制
一、EnableAutoConfiguration注解的本质是一个@Import
import了一个EnableAutoConfigurationImportSelector类,而@import注解是归属于@Configuration注解的
所以这个注解应该是被@Configuration注解解析器来解析的
二、EnableAutoConfigurationImportSelector继承至DeferredImportSelector--->ImportedSelector
1:ImportSelector接口,顾名思义,是对@Import注解的选择器
2:接口方法返回一个配置列表,给@Configuration标注的Java Config类使用
3:Configuration会递归处理调用所有的import配置
/**
* Select and return the names of which class(es) should be imported based on
* the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
*/
String[] selectImports(AnnotationMetadata importingClassMetadata);
三、Spring如何从@Configuration到@EnableAutoConfiguration
1:SpringApplication为一些注解添加后置处理器:(注意,这里回到SpringFramework context框架中了,是Spring容器管理的通用框架和逻辑)
SpringApplication使用AnnotatedBeanDefinitionReader解析基于注解的Java配置,在AnnotatedBeanDefinitiaonReader构造方法中,AnnotationConfigUtils.registerAnnotationConfigProcessors(registry)为Java配置所使用到的注解添加后置处理器,其中有一个为ConfigurationClassPostProcessor
2:调用链如下
找到所有的@Configuration类:ConfigurationClassPostProcessor.processConfigBeanDefinitions()
使用ConfigurationClassParser解析每个配置类:ConfigurationClassParser.parse()---> processConfigurationClass()---> doProcessConfigurationClass()
这个解析过程中,有一步是处理@import注解的:ConfigurationClassParser.processImports()
最后调用DeferredImportSelector.selectImports()接口方法:selector.selectImports(currentSourceClass.getMetadata())
四、DeferredImportSelector内部机制
public String[] selectImports(AnnotationMetadataannotationMetadata) {
//是否开启自动配置
if (!isEnabled(annotationMetadata)){
return NO_IMPORTS;
}
try {
//加载Spring内部自动配置的默认原属性
AutoConfigurationMetadataautoConfigurationMetadata=AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AnnotationAttributes attributes =getAttributes(annotationMetadata);
//加载需要被自动配置类,最关键的一个地方
//使用SpringFactoriesLoader,"EnableAutoConfiguration"作为key,加载META-INF/spring.factories中的值
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);
//处理@Condition注解,内部还是使用spring.factories加载一个key为"AutoConfigurationImportFilter"的过滤器
//org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
//org.springframework.boot.autoconfigure.condition.OnClassCondition
configurations =filter(configurations, autoConfigurationMetadata);
//发消息,给后续处理
//事件监听器还是通过SpringFactoriesLoader加载spring.factories中key为"AutoConfigurationImportListener"
//的所有监听器
fireAutoConfigurationImportEvents(configurations,exclusions);
//返还给ConfigurationClassParser继续处理
return configurations.toArray(newString[configurations.size()]);
}catch (IOException ex) {
throw newIllegalStateException(ex);
}
}
五、SpringLoaderFactories机制
SpringFactoriesLoader 会查询 META-INF/spring.factories文件。当找到 spring.factories 文件后,SpringFactoriesLoader 将使用key名,查找并返回
一个包含所需配置的列表List<String> configurations。
(EnableAutoConfiguration的spring.factories在spring-boot-autoconfigure包中)
这里我仅列出需要加载的自动配置,如下:
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
....
public void onAutoConfigurationImportEvent(AutoConfigurationImportEvent event) {
if (this.beanFactory != null) {
ConditionEvaluationReport report = ConditionEvaluationReport
.get(this.beanFactory);
report.recordEvaluationCandidates(event.getCandidateConfigurations());
report.recordExclusions(event.getExclusions());
}
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = (beanFactory instanceof ConfigurableListableBeanFactory
? (ConfigurableListableBeanFactory) beanFactory : null);
}