Open zyllt opened 5 years ago
该类的核心方法就是selectImports,下面是源码和一些自己的阅读注释,英文渣可能不准确
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
/**
* {@link EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY} = false时此自动配置不启用,默认true
*/
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
/**
* 加载{@link AutoConfigurationMetadataLoader.PATH}文件(此文件是spring boot autoconfiguration模块编译时自动生成,保存所有的autoconfiguration的conditional )
* 在调用AutoConfigurationImportFilter被使用(OnClassCondition)
*/
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
/**
* *获取{@link EnableAutoConfiguration} 属性,肯定有值
*/
AnnotationAttributes attributes = getAttributes(annotationMetadata);
//获取自动配置的类名称集合,使用SpringFactoriesLoader
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
//去重,转set
configurations = removeDuplicates(configurations);
//获取需要排除的类,通过注解或者配置
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
//校验是否有无效的排除类,有的话就抛出异常 (暂时不明白这么做的意义)
checkExcludedClasses(configurations, exclusions);
//从需要自动配置的类中删除需要排除的类
configurations.removeAll(exclusions);
/**
* 执行 {@link AutoConfigurationImportFilter},此时也可以排除不想使用自动配置的的类
*
* 其实是触发了 {@link org.springframework.boot.autoconfigure.condition.OnClassCondition}排除了
* {@link org.springframework.boot.autoconfigure.condition.ConditionalOnClass} 不存在的类
*
*/
configurations = filter(configurations, autoConfigurationMetadata);
//加载、触发 AutoConfigurationImportListener
fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
}
这个方法比较简单,几个逻辑都是很容易理解的。其中比较核心的逻辑就是获取所有的@EnableAutoConfiguration
类名称(使用SpringFactoriesLoader
来加载,一般我们也可以这么做)
/**
* Return the auto-configuration class names that should be considered. By default
* this method will load candidates using {@link SpringFactoriesLoader} with
* {@link #getSpringFactoriesLoaderFactoryClass()}.
* @param metadata the source metadata
* @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
* attributes}
* @return a list of candidate configurations
*/
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
List<String> 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;
}
/**
* Return the class used by {@link SpringFactoriesLoader} to load configuration
* candidates.
* @return the factory class
*/
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
还有就是filter方法,该方法会验证所有的 @EnableAutoConfiguration
类然后排除不符合条件的自动配置类(配置了ConditionalOnClass
注解的类不存在)
private List<String> filter(List<String> configurations,
AutoConfigurationMetadata autoConfigurationMetadata) {
long startTime = System.nanoTime();
String[] candidates = StringUtils.toStringArray(configurations);
boolean[] skip = new boolean[candidates.length];
boolean skipped = false;
//获取 AutoConfigurationImportFilter,默认是 OnClassCondition
for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
//调用filter的aware方法,如果存在
invokeAwareMethods(filter);
boolean[] match = filter.match(candidates, autoConfigurationMetadata);
for (int i = 0; i < match.length; i++) {
if (!match[i]) {
skip[i] = true;
skipped = true;
}
}
}
if (!skipped) {
return configurations;
}
List<String> 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);
}
其中默认存在的AutoConfigurationImportFilter
只有OnClassCondition
,通过这个filter来验证配置了注解ConditionalOnClass
是否合法
@Override
public boolean[] match(String[] autoConfigurationClasses,
AutoConfigurationMetadata autoConfigurationMetadata) {
ConditionEvaluationReport report = getConditionEvaluationReport();
//返回验证结果,这个结果的长度和autoConfigurationClasses相同,如果验证通过对应的结果为null或者ConditionOutcome.match=true
ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses,
autoConfigurationMetadata);
boolean[] match = new boolean[outcomes.length];
for (int i = 0; i < outcomes.length; i++) {
match[i] = (outcomes[i] == null || outcomes[i].isMatch());
if (!match[i] && outcomes[i] != null) {
//验证不通过的输出log
logOutcome(autoConfigurationClasses[i], outcomes[i]);
if (report != null) {
report.recordConditionEvaluation(autoConfigurationClasses[i], this,
outcomes[i]);
}
}
}
return match;
}
private ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
AutoConfigurationMetadata autoConfigurationMetadata) {
// Split the work and perform half in a background thread. Using a single
// additional thread seems to offer the best performance. More threads make
// things worse
//有个独立的线程处理一半,主线程处理一半
int split = autoConfigurationClasses.length / 2;
//创建StandardOutcomesResolver,并且启动一个独立线程来执行一半任务
OutcomesResolver firstHalfResolver = createOutcomesResolver(
autoConfigurationClasses, 0, split, autoConfigurationMetadata);
//主线程执行StandardOutcomesResolver
OutcomesResolver secondHalfResolver = new StandardOutcomesResolver(
autoConfigurationClasses, split, autoConfigurationClasses.length,
autoConfigurationMetadata, this.beanClassLoader);
ConditionOutcome[] secondHalf = secondHalfResolver.resolveOutcomes();
//这个实际是用thread.join()来保证独立线程任务执行完成了
ConditionOutcome[] firstHalf = firstHalfResolver.resolveOutcomes();
//合并2个结果
ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];
System.arraycopy(firstHalf, 0, outcomes, 0, firstHalf.length);
System.arraycopy(secondHalf, 0, outcomes, split, secondHalf.length);
return outcomes;
}
StandardOutcomesResolver
的resolveOutcomes()
方法执行逻辑,其实就是验证ConditonalOnClass
配置的class是否存在
@Override
public ConditionOutcome[] resolveOutcomes() {
return getOutcomes(this.autoConfigurationClasses, this.start, this.end,
this.autoConfigurationMetadata);
}
private ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
int start, int end, AutoConfigurationMetadata autoConfigurationMetadata) {
ConditionOutcome[] outcomes = new ConditionOutcome[end - start];
for (int i = start; i < end; i++) {
String autoConfigurationClass = autoConfigurationClasses[i];
//从PropertiesAutoConfigurationMetadata 注解ConditionalOnClass的类,其实就是获取这个类有使用@ConditionalOnClass修饰时设置的类
Set<String> candidates = autoConfigurationMetadata
.getSet(autoConfigurationClass, "ConditionalOnClass");
if (candidates != null) {
//判断这个类是否存在,如果存在就返回null
outcomes[i - start] = getOutcome(candidates);
}
}
return outcomes;
}
从以上可以看出如果想试用自动配置,首先要@EnableAutoConfiguration
,然后还要配置META-INF/spring.factories ,例如
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
另外还有一种编程式自动配置的方案就是使用@ImportAutoConfiguration
注解。这个注解的实现方式比较简单,是通过ImportAutoConfigurationImportSelector
,这个类继承了AutoConfigurationImportSelector
然后重写了其获取自动配置类的部分,其他没啥变化
实现了DeferredImportSelector接口,用于处理@EnableAutoConfiguration,如果需要做一些定制化操作,可以重写该类