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#getOutcomesprivate 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#ClassNameFilterprotected 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#postProcessBeanFactoryConfigurationClassPostProcessor#processConfigBeanDefinitions
-
ConfigurationClassParser#parseConfigurationClassParser#processConfigurationClassConfigurationClassParser#doProcessConfigurationClassConfigurationClassParser#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就是一个封装类,封装了ConfigurationClass和DeferredImportSelector
//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());
}