3. Spring Boot之自动装配

230 阅读6分钟

Spring Boot自动装配原理

@SpringBootApplication注解:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
    ...
}

由上述源代码可知@SpringBootApplication注解由一下三个注解组成

  • @SpringBootConfiguration
    • @Configuration
  • @EnableAutoConfiguration 激活自动装配
  • @ComponentScan

我们探索Spring Boot的自动装配,主要就是看@EnableAutoConfiguration的内部原理和实现。

@EnableAutoConfiguration基本原理

Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

@EnableAutoConfiguration是Enable模块驱动的设计,主要就是结合@Configuration注解,在@ConfigurationClassPostProcessor回调时处理@EnableAutoConfiguration注解上标注的@Import({AutoConfigurationImportSelector.class})信息,这个处理过程简略概括为特殊的条件装配,即:我需要向Spring上下文中根据当前的条件注册哪些Bean。

AutoConfigurationImportSelector#selectImports(...)

AutoConfigurationImportSelector的核心源码如下所示:

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
    ...
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            // 加载自动装配的元信息
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
            // 根据元信息获取AutoConfigurationEntry
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }
    ...
}

我们接下来详细对上面的方法进行分析

getAutoConfigurationEntry()

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
			AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
        // 获取@EnableAutoConfiguration标注的元信息 
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
        // 获取自动装配的候选类集合
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    	// 移除重复对象(为啥会重复呢)
		configurations = removeDuplicates(configurations);
    	// 移除自动装配的排出名单
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
    
    	// 过滤
		configurations = filter(configurations, autoConfigurationMetadata);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}
getCandidateConfigurations读取候选自动装配组件
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;
	}

protected Class<?> getSpringFactoriesLoaderFactoryClass() {
		return EnableAutoConfiguration.class;
	}
SpringFactoriesLoader.loadFactoryNames
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
    //@EnableAutoConfiguration的全类名 package+类名组成
        String factoryClassName = factoryClass.getName();
        // classLoader是Bean的ClassLoader
    	// 获取全部属性的Map,再根据key :@EnableAutoConfiguration获取List列表(即自动装配类的类名)
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
    }
// 获取jar包和我们Spring Boot应用程序中所有spring.factories文件中的全部属性
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
    	// private static final Map<ClassLoader, MultiValueMap<String, String>> cache = //  new ConcurrentReferenceHashMap<>();
    // ConcurrentReferenceHashMap 软引用对象,垃圾收集器根据内存需求酌情清除这些对象。软引用最常用于实现对内存敏感的缓存。
		MultiValueMap<String, String> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

		try {
            // public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
			Enumeration<URL> urls = (classLoader != null ?
					classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
					ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
			result = new LinkedMultiValueMap<>();
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					String factoryClassName = ((String) entry.getKey()).trim();
					for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
                        // key这里是 : @EnableAutoConfiguration  value:自动装配实现类的类名
						result.add(factoryClassName, factoryName.trim());
					}
				}
			}
			cache.put(classLoader, result);
			return result;
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
}

主要是先从缓存中获取(缓存设计用到了软引用,这样一个单机版的JVM缓存 Map其实特别巧妙,让人联想到Redis处理缓存的基本方针:即先从Redis中查询,如果Redis中有数据则直接返回,如果没有则从数据库查,将查询结果写入Redis再返回查询结果)

软饮用对象遇到GC的时候会被选择性的回收,在我认为可能出现OOM的情况下就会回收软饮用对象,正常GC应该不会回收,如果那么容易被GC回收,那么我们程序运行时就不可以利用其实现稳定的缓存。

然后再使用ClassLoader去每一个jar包下面的META-INF/spring.factories文件,然后遍历这些文件,将文件转换成Properties对象,这个不难理解,因为spring.factories文件中的配置本身就是key value的,而Properties本身就是HashTable类型,也是key value类型的。

我们看一下spring.factories示例文件

# 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.CloudServiceConnectorsAutoConfiguration,\
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.CassandraReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\
...
getExclusions - 排除自动装配组件
private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";

protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		Set<String> excluded = new LinkedHashSet<>();
		excluded.addAll(asList(attributes, "exclude"));
		excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
		excluded.addAll(getExcludeAutoConfigurationsProperty());
		return excluded;
	}

	private List<String> getExcludeAutoConfigurationsProperty() {
		if (getEnvironment() instanceof ConfigurableEnvironment) {
			Binder binder = Binder.get(getEnvironment());
			return binder.bind(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class).map(Arrays::asList)
					.orElse(Collections.emptyList());
		}
		String[] excludes = getEnvironment().getProperty(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class);
		return (excludes != null) ? Arrays.asList(excludes) : Collections.emptyList();
	}
filter过滤自动装配组件
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;
		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<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
  protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
		return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
	}

SpringFactoriesLoader#loadFactories

public static <T> List<T> loadFactories(Class<T> factoryClass, @Nullable ClassLoader classLoader) {
		Assert.notNull(factoryClass, "'factoryClass' must not be null");
		ClassLoader classLoaderToUse = classLoader;
		if (classLoaderToUse == null) {
			classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
		}
		List<String> factoryNames = loadFactoryNames(factoryClass, classLoaderToUse);
		if (logger.isTraceEnabled()) {
			logger.trace("Loaded [" + factoryClass.getName() + "] names: " + factoryNames);
		}
		List<T> result = new ArrayList<>(factoryNames.size());
		for (String factoryName : factoryNames) {
			result.add(instantiateFactory(factoryName, factoryClass, classLoaderToUse));
		}
		AnnotationAwareOrderComparator.sort(result);
		return result;
	}

获取到的有

# 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

我们会对这些AutoConfigurationImportFilter遍历调用其match方法,实质就是下面的方法

// FilteringSpringBootCondition
@Override
	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;
	}
OnClassCondition

我们以OnClassCondition为例,分析其调用match方法的逻辑

// 这个是match方法的核心
ConditionOutcome[] outcomes = getOutcomes(autoConfigurationClasses, autoConfigurationMetadata);
// OnClassCondition
// 获取条件匹配的结果
@Override
	protected final 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;
		OutcomesResolver firstHalfResolver = createOutcomesResolver(autoConfigurationClasses, 0, split,
				autoConfigurationMetadata);
		OutcomesResolver secondHalfResolver = new StandardOutcomesResolver(autoConfigurationClasses, split,
				autoConfigurationClasses.length, autoConfigurationMetadata, getBeanClassLoader());
		ConditionOutcome[] secondHalf = secondHalfResolver.resolveOutcomes();
		ConditionOutcome[] firstHalf = firstHalfResolver.resolveOutcomes();
		ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];
		System.arraycopy(firstHalf, 0, outcomes, 0, firstHalf.length);
		System.arraycopy(secondHalf, 0, outcomes, split, secondHalf.length);
		return outcomes;
	}
  • new StandardOutcomesResolver(...)

    • StandardOutcomesResolver#resolveOutcomes

      • StandardOutcomesResolver#getOutcomes

        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) {
                            // 获取候选组件中的@ConditionalOnClass注解的属性值
        					String candidates = autoConfigurationMetadata.get(autoConfigurationClass, "ConditionalOnClass");
        					if (candidates != null) {
                                // 1
        						outcomes[i - start] = getOutcome(candidates);
        					}
        				}
        			}
        			return outcomes;
        		}
        // 1
        private ConditionOutcome getOutcome(String candidates) {
        			try {
        				if (!candidates.contains(",")) {
                            
                            // 2
        					return getOutcome(candidates, this.beanClassLoader);
        				}
        				for (String candidate : StringUtils.commaDelimitedListToStringArray(candidates)) {
                            // 2
        					ConditionOutcome outcome = getOutcome(candidate, this.beanClassLoader);
        					if (outcome != null) {
        						return outcome;
        					}
        				}
        			}
        			catch (Exception ex) {
        				// We'll get another chance later
        			}
        			return null;
        		}
        // 2 这是最终被调用的方法,调用链的底层
        private ConditionOutcome getOutcome(String className, ClassLoader classLoader) {			
            // 这里是看@ConditionalOnClass对应的类能不能用ClassLoader加载到,如果可以加载到什么都不做
        			if (ClassNameFilter.MISSING.matches(className, classLoader)) {
        				return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class)
        						.didNotFind("required class").items(Style.QUOTE, className));
        			}
        			return null;
        		}
        
        

        FilteringSpringBootCondition#ClassNameFilter

        protected enum ClassNameFilter {
        
        		PRESENT {
        
        			@Override
        			public boolean matches(String className, ClassLoader classLoader) {
        				return isPresent(className, classLoader);
        			}
        
        		},
        
        		MISSING {
        			// 我们走这个逻辑
        			@Override
        			public boolean matches(String className, ClassLoader classLoader) {
        				return !isPresent(className, classLoader);
        			}
        
        		};
            public static boolean isPresent(String className, ClassLoader classLoader) {
        			if (classLoader == null) {
        				classLoader = ClassUtils.getDefaultClassLoader();
        			}
        			try {
        				forName(className, classLoader);
        				return true;
        			}
        			catch (Throwable ex) {
        				return false;
        			}
        		}
        
        		private static Class<?> forName(String className, ClassLoader classLoader) throws ClassNotFoundException {
        			if (classLoader != null) {
        				return classLoader.loadClass(className);
        			}
        			return Class.forName(className);
        		}
        }
        
@EnableAutoConfiguration自动装配事件
// AutoConfigurationImportSelector
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
			AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		configurations = removeDuplicates(configurations);
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		configurations = filter(configurations, autoConfigurationMetadata);
    	// 自动装配事件
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}
private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
       // 获取自动装配的事件监听器
		List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
		if (!listeners.isEmpty()) {
            // 发布事件
			AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
            // 遍历事件监听器
			for (AutoConfigurationImportListener listener : listeners) {
				invokeAwareMethods(listener);
                // 绑定监听
				listener.onAutoConfigurationImportEvent(event);
			}
		}
}
protected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners() {
		return SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class, this.beanClassLoader);
	}
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener
...
class ConditionEvaluationReportAutoConfigurationImportListener
		implements AutoConfigurationImportListener, BeanFactoryAware {

	private ConfigurableListableBeanFactory beanFactory;

	@Override
	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;
	}

}

通过对上面代码的列举,我们也可以按照其实现规则实现自定义的AutoConfigurationImportListener

实现自定义AutoConfigurationImportListener

(1)实现AutoConfigurationImportListener接口

/**

 * {@link AutoConfigurationImportListener}自定义实现
   *
 * @author ajin
   */

public class DefaultAutoConfigurationImportListener implements AutoConfigurationImportListener {
@Override
public void onAutoConfigurationImportEvent(AutoConfigurationImportEvent event) {
    // 获取当前ClassLoader
    ClassLoader classLoader = event.getClass().getClassLoader();

    // 候选的自动装配Class名单
    List<String> candidates = SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, classLoader);

    // 实际的自动装配 Class名单
    List<String> configurations = event.getCandidateConfigurations();
    // 排除的自动装配Class 名单
    Set<String> exclusions = event.getExclusions();

    // 输出各自数量
    System.out.printf("自动装配Class名单 -候选数量 :%d,实际数量: %d 排除数量: %d", candidates.size(),
            configurations.size(), exclusions.size());

    // 输出实际和排出的自动装配Class名单
    System.out.println("实际的自动装配Class名单: ");
    event.getCandidateConfigurations().forEach(System.out::println);

    System.out.println("排除的自动装配Class名单 :");
    event.getExclusions().forEach(System.out::println);
 }
}

(2) 新建META-INF/spring.factories文件

org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
com.thinkinginspringboot.automaticalasembly.event.DefaultAutoConfigurationImportListener

(3) 引导类

/**
 * @author ajin
 */
@EnableAutoConfiguration(exclude = SpringApplicationAdminJmxAutoConfiguration.class)
public class EnableAutoConfigurationBootstrap {

    public static void main(String[] args) {
        new SpringApplicationBuilder(EnableAutoConfigurationBootstrap.class)
                .web(WebApplicationType.NONE)
                .run(args).close();
    }
}

启动引导类,自动装配完成后,会引发AutoConfigurationImportListener监听,控制台输出如下:

自动装配Class名单 -候选数量 :117,实际数量: 21 排除数量: 1实际的自动装配Class名单: 
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration
org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration
org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration
org.spr ingframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration
排除的自动装配Class名单 :
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration

思考: 之前听别人说Spring Boot就是设定一些默认配置项的框架来简化开发中的配置工作,让开发人员更方便得开发业务模块,现在一想真是这个道理,并且这个过程中@EnableAutoConfiguration做了大部分的工作。

@EnableAutoConfiguration模块驱动逻辑

@EnableAutoConfiguration属于@Enable模块驱动,所以其本身是借助于ConfigurationClassPostProcessor来处理的。

我们梳理一下调用链路:

  • ConfigurationClassPostProcessor#postProcessBeanFactory

    • ConfigurationClassPostProcessor#processConfigBeanDefinitions
  • ConfigurationClassParser#parse

    • ConfigurationClassParser#processConfigurationClass
    • ConfigurationClassParser#doProcessConfigurationClass
      • ConfigurationClassParser#processImports
// `ConfigurationClassParser#processImports`
for (SourceClass candidate : importCandidates) {
					if (candidate.isAssignable(ImportSelector.class)) {
						// Candidate class is an ImportSelector -> delegate to it to determine imports
						Class<?> candidateClass = candidate.loadClass();
						ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
						ParserStrategyUtils.invokeAwareMethods(
								selector, this.environment, this.resourceLoader, this.registry);		
                        // @EnableAutoConfiguration元标注中的@Import属性值AutoConfigurationImportSelector是DeferredImportSelector的实现类,会进行特殊处理
						if (selector instanceof DeferredImportSelector) {
                            // 下面会展开
							this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
						}
						else {
							String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
							Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
							processImports(configClass, currentSourceClass, importSourceClasses, false);
						}
					}
    ...         

我们列出这个handle方法的详细逻辑

// ConfigurationClassParser.DeferredImportSelectorHandler#handle(...)
private class DeferredImportSelectorHandler {
		@Nullable
		private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();
    
 public void handle(ConfigurationClass configClass, DeferredImportSelector    importSelector) {
			DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(
					configClass, importSelector);
			if (this.deferredImportSelectors == null) {
				DeferredImportSelectorGroupingHandler handler = new       DeferredImportSelectorGroupingHandler();
				handler.register(holder.DeferredImportSelectorHandler
				handler.processGroupImports();
			}
			else {
				this.deferredImportSelectors.add(holder);
			}
 ....
}

DeferredImportSelectorHolder就是一个封装类,封装了ConfigurationClassDeferredImportSelector

  //ConfigurationClassParser.DeferredImportSelectorHolder
	private static class DeferredImportSelectorHolder {

		private final ConfigurationClass configurationClass;

		private final DeferredImportSelector importSelector;
        ...
    }

handle方法中最核心的部分为

if (this.deferredImportSelectors == null) {
				DeferredImportSelectorGroupingHandler handler = new       DeferredImportSelectorGroupingHandler();
				handler.register(holder.DeferredImportSelectorHandler
				handler.processGroupImports();
			}

我们深入看一下DeferredImportSelectorGroupingHandler

ConfigurationClassParser#DeferredImportSelectorGroupingHandler

private class DeferredImportSelectorGroupingHandler {

		private final Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>();

		private final Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>();
		...

	}

DeferredImportSelectorGroupingHandler#register

public void register(DeferredImportSelectorHolder deferredImport) {
            // 1.获取AutoConfigurationImportSelector的Group: AutoConfigurationGroup.class
   			// Class<AutoConfigurationGroup>对象
			Class<? extends Group> group = deferredImport.getImportSelector()
					.getImportGroup();
			DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
					(group != null ? group : deferredImport),
					key -> new DeferredImportSelectorGrouping(createGroup(group)));
			grouping.add(deferredImport);
			this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
					deferredImport.getConfigurationClass());
		}
AutoConfigurationImportSelector#getImportGroup()
@Override
public Class<? extends Group> getImportGroup() {  
    return AutoConfigurationGroup.class;
}
groupings
private class DeferredImportSelectorGroupingHandler {

		private final Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>();
    ...
}        

DeferredImportSelectorGroupingHandler#processGroupImports

public void processGroupImports() {
			for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
                // 1
				grouping.getImports().forEach(entry -> {
					ConfigurationClass configurationClass = this.configurationClasses.get(
							entry.getMetadata());
					try {
						processImports(configurationClass, asSourceClass(configurationClass),
								asSourceClasses(entry.getImportClassName()), false);
					}
					catch (BeanDefinitionStoreException ex) {
						throw ex;
					}
					catch (Throwable ex) {
						throw new BeanDefinitionStoreException(
								"Failed to process import candidates for configuration class [" +
										configurationClass.getMetadata().getClassName() + "]", ex);
					}
				});
			}
		
    private Group createGroup(@Nullable Class<? extends Group> type) {
			Class<? extends Group> effectiveType = (type != null ? type
					: DefaultDeferredImportSelectorGroup.class);
			Group group = BeanUtils.instantiateClass(effectiveType);
			ParserStrategyUtils.invokeAwareMethods(group,
					ConfigurationClassParser.this.environment,
					ConfigurationClassParser.this.resourceLoader,
					ConfigurationClassParser.this.registry);
			return group;
	}
DeferredImportSelectorGrouping#getImports
/**
		 * Return the imports defined by the group.
		 * @return each import with its associated configuration class
		 */
		public Iterable<Group.Entry> getImports() {
			for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
				this.group.process(deferredImport.getConfigurationClass().getMetadata(),
						deferredImport.getImportSelector());
			}
			return this.group.selectImports();
  }
     @Override
		public Iterable<Entry> selectImports() {
			if (this.autoConfigurationEntries.isEmpty()) {
				return Collections.emptyList();
			}
			Set<String> allExclusions = this.autoConfigurationEntries.stream()
					.map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());
			Set<String> 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());
		}