spring boot 通过@EnableAutoConfiguration开启autoconfigure功能。
点开注解,可以看到有一个@Import注解,AutoConfigurationImportSelector,实现了DeferredImportSelector接口,DeferredImportSelector和ImportSelector有所区别,DeferredImportSelector将会执行DeferredImportSelector.Group中的process方法,并且接着调用selectImports,先看process
@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
() -> String.format("Only %s implementations are supported, got %s",
AutoConfigurationImportSelector.class.getSimpleName(),
deferredImportSelector.getClass().getName()));
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
.getAutoConfigurationEntry(annotationMetadata);
this.autoConfigurationEntries.add(autoConfigurationEntry);
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
看getAutoConfigurationEntry方法,在getCandidateConfigurations中,从META-INF/spring.factories文件中获取所有键是org.springframework.boot.autoconfigure.EnableAutoConfiguration的类的集合configurations,接着移除重复的,再从annotation的元数据中获取到excluede,以及filter,执行过滤排除,进一步得到需要的类。
/**
* Return the {@link AutoConfigurationEntry} based on the {@link AnnotationMetadata}
* of the importing {@link Configuration @Configuration} class.
* @param annotationMetadata the annotation metadata of the configuration class
* @return the auto-configurations that should be imported
*/
protected AutoConfigurationEntry getAutoConfigurationEntry(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 = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
这里要详细看一看filter的过程,首先会获取一个filters的集合
protected List getAutoConfigurationImportFilters() {
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
}
private ConfigurationClassFilter getConfigurationClassFilter() {
if (this.configurationClassFilter == null) {
List filters = getAutoConfigurationImportFilters();
for (AutoConfigurationImportFilter filter : filters) {
invokeAwareMethods(filter);
}
this.configurationClassFilter = new ConfigurationClassFilter(this.beanClassLoader, filters);
}
return this.configurationClassFilter;
}
这里可以看到,从META-INF/spring.factories文件中获取AutoConfigurationImportFilter的实现类,当前默认只有spring-boot-autoconfigure这个包下面的META-INF/spring.factories文件存在,而这个文件中有三个AutoConfigurationImportFilter的实现类,、分别是OnClassCondition,OnWebApplicationCondition以及OnBeanCondition。
接着创建了一个ConfigurationClassFilter,重点看一下这个构造方法
ConfigurationClassFilter(ClassLoader classLoader, List filters) {
this.autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(classLoader);
this.filters = filters;
}
调用了AutoConfigurationMetadataLoader的loadMetadata方法,方法中会去扫描一个固定的路径META-INF/spring-autoconfigure-metadata.properties,将所有该路径下文件中的配置都加载到一个properties中,接着创建一个PropertiesAutoConfigurationMetadata返回
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);
}
}
static AutoConfigurationMetadata loadMetadata(Properties properties) {
return new PropertiesAutoConfigurationMetadata(properties);
}
接着调用ConfigurationClassFilter的filter方法,分析一下代码,首先循环调用三个filter类,参数分别是从META-INF/spring.factories中获取的configurations集合以及从META-INF/spring-autoconfigure-metadata.properties中获取的autoConfigurationMetadata集合,然后进行过滤,符合的留下,不符合的置为空,过滤完成之后,接着再次循环,将空的移除,返回留下来的。
List filter(List configurations) {
long startTime = System.nanoTime();
String[] candidates = StringUtils.toStringArray(configurations);
boolean skipped = false;
for (AutoConfigurationImportFilter filter : this.filters) {
boolean[] match = filter.match(candidates, this.autoConfigurationMetadata);
for (int i = 0; i < match.length; i++) {
if (!match[i]) {
candidates[i] = null;
skipped = true;
}
}
}
if (!skipped) {
return configurations;
}
List result = new ArrayList<>(candidates.length);
for (String candidate : candidates) {
if (candidate != null) {
result.add(candidate);
}
}
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 result;
}
}
所以要看看三个filter中究竟做了什么事情。
首先看OnClassCondition的调用
public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
ConditionEvaluationReport report = ConditionEvaluationReport.find(this.beanFactory);
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) {
logOutcome(autoConfigurationClasses[i], outcomes[i]);
if (report != null) {
report.recordConditionEvaluation(autoConfigurationClasses[i], this, outcomes[i]);
}
}
}
return match;
}
首先向spring容器中注册一个ConditionEvaluationReport并返回
/**
* Obtain a {@link ConditionEvaluationReport} for the specified bean factory.
* @param beanFactory the bean factory
* @return an existing or new {@link ConditionEvaluationReport}
*/
public static ConditionEvaluationReport get(ConfigurableListableBeanFactory beanFactory) {
synchronized (beanFactory) {
ConditionEvaluationReport report;
if (beanFactory.containsSingleton(BEAN_NAME)) {
report = beanFactory.getBean(BEAN_NAME, ConditionEvaluationReport.class);
}
else {
report = new ConditionEvaluationReport();
beanFactory.registerSingleton(BEAN_NAME, report);
}
locateParent(beanFactory.getParentBeanFactory(), report);
return report;
}
}
接着调用getOutcomes方法,这里直接去看核心的代码,会创建一个StandardOutcomesResolver,调用getOutcomes方法,注意这里的autoConfigurationClasses就是之前的configurations集合,而autoConfigurationMetadata自然是之前的autoConfigurationMetadata集合,这里是循环configurations集合,从autoConfigurationMetadata这个properties的集合中获取当前configuration的名称加上.再加上ConditionalOnClass,假设当前configuration名称是com.aa.xx那么结合就是com.aa.xx.ConditionalOnClass这样一个properties键名,从而获取对应的值。
大致流程先说明一下,这里就是从META-INF/spring.factories中获取到的autoconfigure的类名A类,然后再从META-INF/spring-autoconfigure-metadata.properties中获取类名加上ConditionalOnClass的键的值,值就是另外一个类B类,就是说autoconfigure的类需要这个类存在才能加载,所以再接下来执行的getOutcome方法就是判断这另外的那个B类存不存在
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];
if (autoConfigurationClass != null) {
String candidates = autoConfigurationMetadata.get(autoConfigurationClass, "ConditionalOnClass");
if (candidates != null) {
outcomes[i - start] = getOutcome(candidates);
}
}
}
return outcomes;
}
再来看getOutcome方法,最后会调用getOutcome方法,首先调用matches方法,方法中就是看能不能用类加载器加载到这个类,如果可以加载返回null,否则就构建一个ConditionOutcome,这个ConditionOutcome表示了ConditionalOnClass这个条件下,没有找到必须的类。
private ConditionOutcome getOutcome(String className, ClassLoader classLoader) {
if (ClassNameFilter.MISSING.matches(className, classLoader)) {
return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class)
.didNotFind("required class").items(Style.QUOTE, className));
}
return null;
}
回到match方法,往下,返回null的是true,否则是false,并且trace级别的日志打印,并且记录到了ConditionEvaluationReport里面
接着第二个filter,OnWebApplicationCondition,在了解了OnClassCondition的原理之后,后面的两个filter功能基本类似,在OnWebApplicationCondition中,从META-INF/spring-autoconfigure-metadata.properties中获取类名加上ConditionalOnWebApplication的值,如果指定是SERVLET,会判断是否能加载org.springframework.web.context.support.GenericWebApplicationContext,如果指定是REACTIVE,会判断能否加载org.springframework.web.reactive.HandlerResult,如果其他,就会判断以上其中一个是否能加载到。其他逻辑和第一个filter基本类似。同样返回一个true和false的集合,再到一个循环中,将false的置为null,因此这三个filter是&&的关系。
private ConditionOutcome getOutcome(String type) {
if (type == null) {
return null;
}
ConditionMessage.Builder message = ConditionMessage.forCondition(ConditionalOnWebApplication.class);
if (ConditionalOnWebApplication.Type.SERVLET.name().equals(type)) {
if (!ClassNameFilter.isPresent(SERVLET_WEB_APPLICATION_CLASS, getBeanClassLoader())) {
return ConditionOutcome.noMatch(message.didNotFind("servlet web application classes").atAll());
}
}
if (ConditionalOnWebApplication.Type.REACTIVE.name().equals(type)) {
if (!ClassNameFilter.isPresent(REACTIVE_WEB_APPLICATION_CLASS, getBeanClassLoader())) {
return ConditionOutcome.noMatch(message.didNotFind("reactive web application classes").atAll());
}
}
if (!ClassNameFilter.isPresent(SERVLET_WEB_APPLICATION_CLASS, getBeanClassLoader())
&& !ClassUtils.isPresent(REACTIVE_WEB_APPLICATION_CLASS, getBeanClassLoader())) {
return ConditionOutcome.noMatch(message.didNotFind("reactive or servlet web application classes").atAll());
}
return null;
}
再看第三个OnBeanCondition,这个filter和之前不同的地方是从META-INF/spring-autoconfigure-metadata.properties中获取类名加上ConditionalOnBean以及ConditionalOnSingleCandidate的值,判断能否加载到,过程和之前都类似。
protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
AutoConfigurationMetadata autoConfigurationMetadata) {
ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];
for (int i = 0; i < outcomes.length; i++) {
String autoConfigurationClass = autoConfigurationClasses[i];
if (autoConfigurationClass != null) {
Set onBeanTypes = autoConfigurationMetadata.getSet(autoConfigurationClass, "ConditionalOnBean");
outcomes[i] = getOutcome(onBeanTypes, ConditionalOnBean.class);
if (outcomes[i] == null) {
Set onSingleCandidateTypes = autoConfigurationMetadata.getSet(autoConfigurationClass,
"ConditionalOnSingleCandidate");
outcomes[i] = getOutcome(onSingleCandidateTypes, ConditionalOnSingleCandidate.class);
}
}
}
return outcomes;
}
最后经过三个filter之后, 筛选出符合条件的configurations
接着,从META-INF/spring.factories文件中获取所有的AutoConfigurationImportListener监听器,发布AutoConfigurationImportEvent事件,当前默认只有一个ConditionEvaluationReportAutoConfigurationImportListener,ConditionEvaluationReportAutoConfigurationImportListener的onAutoConfigurationImportEvent方法接收事件
取出ConditionEvaluationReport,保存了所有的configurations以及需要排除的excludes,返回。
接着在调用selectImports方法的时候进行排除,以及进行一个排序操作
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());
}
最后返回的就是需要生成Bean的类型的迭代器。