目录
一、process
1、getAutoConfigurationMetadata
2、getAutoConfigurationEntry
1)、获取EnableAutoConfiguration注解的exclude和excludeName属性值
2)、获取spring.factories中EnableAutoConfiguration的配置值
3)、removeDuplicates(去重)
4)、获取需要排除(不自动装配)的类
5)、checkExcludedClasses(检查需要排除的项目)
6)、剔除排除项
6)、发送AutoConfigurationImportEvent事件
7)、创建AutoConfigurationEntry对象返回
二、selectImports
继续上一篇,知道了执行时机和调用顺序,继续分析两个方法的逻辑,是怎样实现自动装配的。开始之前先看看其类结构(属性)AutoConfigurationImportSelector.AutoConfigurationGroup
private static class AutoConfigurationGroup
implements DeferredImportSelector.Group, BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware {
// 存储注解对象关系
private final Map entries = new LinkedHashMap<>();
// 存储自动装配的数据
private final List autoConfigurationEntries = new ArrayList<>();
private ClassLoader beanClassLoader;
private BeanFactory beanFactory;
private ResourceLoader resourceLoader;
// 存储自动装配的,后置处理器,默认order值等信息
private AutoConfigurationMetadata autoConfigurationMetadata;
}
@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
// 断言判断,肯定为true
Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, // 省略部分代码);
// 向上转型,调用父类的方法
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
.getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
// 添加到autoConfigurationEntries属性中
this.autoConfigurationEntries.add(autoConfigurationEntry);
// 将bean信息添加到entries(Map)中
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
获取AutoConfigurationEntry类型的返回结果,组装数据到AutoConfigurationGroup的autoConfigurationEntries和entries中。主要的方法在getAutoConfigurationMetadata中,但是在调用前会加载autoConfigurationMetadata数据。
private AutoConfigurationMetadata getAutoConfigurationMetadata() {
if (this.autoConfigurationMetadata == null) {
this.autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
}
return this.autoConfigurationMetadata;
}
static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
// String PATH = "META-INF/spring-autoconfigure-metadata.properties";
return loadMetadata(classLoader, PATH);
}
static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {
try {
Enumeration urls = (classLoader != null) ? classLoader.getResources(path)
: ClassLoader.getSystemResources(path);
Properties properties = new Properties();
while (urls.hasMoreElements()) {
properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource(urls.nextElement())));
}
return loadMetadata(properties);
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]", ex);
}
}
查询的文件路径为 "META-INF/spring-autoconfigure-metadata.properties",总共有488项key、value对应值。并将其值加载成为Properties类型数据。先看看配置文件大概的内容:
org...RestTemplateAutoConfiguration.AutoConfigureAfter=org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration
org...CassandraReactiveDataAutoConfiguration.ConditionalOnClass=com.datastax.driver.core.Cluster,reactor.core.publisher.Flux,org.springframework.data.cassandra.core.ReactiveCassandraTemplate
org...JerseyAutoConfiguration.AutoConfigureOrder=-2147483648
大致有三种类型(为后续spring.factories中的自动装配类,进行条件判断,过滤使用):
1)、...XXAutoConfiguration.AutoConfigureAfter 谁的自动装配的后置处理器类型
2)、...XXAutoConfiguration.ConditionalOnClass 谁的自动装配的装配条件
3)、...XXAutoConfiguration.AutoConfigureorder 谁的自动装配的排序字段值
再继续看看最后加装的类型(最好加装为PropertiesAutoConfigurationMetadata类型,存放到Spring的Properties类型中,就是一个Hashtable):
static AutoConfigurationMetadata loadMetadata(Properties properties) {
return new PropertiesAutoConfigurationMetadata(properties);
}
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
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);
}
只是默认情况下使用@EnableAutoConfiguration直接都是直接使用的@SpringBootApplication,所以获取到的属性值都为默认值(为空)。
protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
// org.springframework.boot.autoconfigure.EnableAutoConfiguration
String name = getAnnotationClass().getName();
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()
+ " annotated with " + ClassUtils.getShortName(name) + "?");
return attributes;
}
在调用前需要查看加载的类型:
protected Class> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List 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;
}
在启动Spring Boot项目时,分析过会加载META-INF/spring.factories中的所有配置信息。正确流程情况下会在SpringApplic
ation.run方法中,加载SpringApplicationRunListener类型时就会去加载该properties中的信息,其中有一项大致为:
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
。。。。。。
protected final List removeDuplicates(List list) {
return new ArrayList<>(new LinkedHashSet<>(list));
}
虽然比较简单,但是是我们在写项目的时候可以进行借鉴的方式。
protected Set getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
Set excluded = new LinkedHashSet<>();
excluded.addAll(asList(attributes, "exclude"));
excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
excluded.addAll(getExcludeAutoConfigurationsProperty());
return excluded;
}
不仅处理了之前getAttributes加载的@EnableConfiguration上的配置值,还添加了getExcludeAutoConfigurationsProperty中,在Environment中加载的值。当然,默认情况下所有值都为空。
循环遍历排除项,如果在自动装配项中不存在需要排除的项,则组装检查异常IllegalStateException并抛出。所以不能随便写排除项。
// 根据上面的排除项集合,剔除排除项
configurations.removeAll(exclusions);
// 根据加载的spring-autoconfigure-metadata.properties条件,进行排除
configurations = filter(configurations, autoConfigurationMetadata);
private List filter(List configurations, AutoConfigurationMetadata
autoConfigurationMetadata) {
long startTime = System.nanoTime();
String[] candidates = StringUtils.toStringArray(configurations);
boolean[] skip = new boolean[candidates.length];
boolean skipped = false;
for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
invokeAwareMethods(filter);
boolean[] match = filter.match(candidates, autoConfigurationMetadata);
for (int i = 0; i < match.length; i++) {
if (!match[i]) {
skip[i] = true;
candidates[i] = null;
skipped = true;
}
}
}
if (!skipped) {
return configurations;
}
List result = new ArrayList<>(candidates.length);
for (int i = 0; i < candidates.length; i++) {
if (!skip[i]) {
result.add(candidates[i]);
}
}
if (logger.isTraceEnabled()) {
int numberFiltered = configurations.size() - result.size();
logger.trace("Filtered " + numberFiltered + " auto configuration class in "
+ TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
}
return new ArrayList<>(result);
}
1)、先获取spring.factories中的AutoConfigurationImportFilter类型。
# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
2)、遍历上面的三种类型,并且回调三种类型的BeanClassLoaderAware、BeanFactoryAware、EnvironmentAware、ResourceLoaderAware接口进行赋值。
3)、再结合spring-autoconfigure-metadata.properties中加载的具体类型调用match方法进行判定。
4)、组装过滤后的最终需要自动装配的类型,返回。
private void fireAutoConfigurationImportEvents(List configurations, Set exclusions) {
List listeners = getAutoConfigurationImportListeners();
if (!listeners.isEmpty()) {
AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
for (AutoConfigurationImportListener listener : listeners) {
invokeAwareMethods(listener);
listener.onAutoConfigurationImportEvent(event);
}
}
}
获取事件监听列表,遍历回调Aware接口,发送AutoConfigurationImportEvent 事件。
监听列表也是自动装配的spring.factories中的AutoConfigurationImportListener类型。
根据需要自动装配的类型列表和需要排除的对象列表,创建AutoConfigurationEntry类型对象返回,为后续的selectImports回调做准备。
@Override
public Iterable selectImports() {
if (this.autoConfigurationEntries.isEmpty()) {
return Collections.emptyList();
}
Set allExclusions = this.autoConfigurationEntries.stream()
.map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream)
.collect(Collectors.toSet());
Set processedConfigurations = this.autoConfigurationEntries.stream()
.map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)
.collect(Collectors.toCollection(LinkedHashSet::new));
processedConfigurations.removeAll(allExclusions);
return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()
.map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName))
.collect(Collectors.toList());
}
1)、从List
2)、从List
3)、从自动装配列表中剔除需要排除的项
4)、将自动装配项进行排序,并且组装成DeferredImportSelector.Group.Entry类型,返回。