一、概述
@EnableAutoConfiguration注解是Spring Boot中配置自动装载的总开关。本文将从@EnableAutoConfiguration入手,尝试通过源码分析增强对Spring Boot的理解。
所用版本:Spring Boot 2.2.0.M5 + Spring Framework 5.2.0.RC1
1. 功能的实现:(Spring Boot部分)
boot.autoconfigure.EnableAutoConfiguration注解
-> @Import了一个AutoConfigurationImportSelector实例
-> AutoConfigurationImportSelector类(implement ImportSelector),实现了selectImports() 方法,用来筛选被@Import的Configuration类(减去exclude等)
2. 接口的调度:(Spring部分)
context.annotation.ConfigurationClassParser类的parse() 方法
-> 调用对应不同BeanDefinition类型的parse() 方法
| -> 调用context.annotation.ConfigurationClassParser.doProcessConfigurationClass()方法处理ConfigurationClass
| -> 调用processImports()方法来处理所有@Import注解
| -> 遍历每个@Import标签,生成被注入的ImportSelector子类的实例
| -> 对于普通ImportSelector,调用其selectImport()方法,筛掉exclude的,再嵌套processImports(),对需要被@Import的类的@Import注解进行处理
| -> 对于DefferedImportSelector,只加入deferredImportSelectors列表中
-> 对defferedImportImportSelectors调用相应handler的process()方法进行处理
-> 对DefferedImportImportSelector调用processImports()
3. 接口在框架中的位置:(其中一条路径,由顶向下)
【Spring Boot部分】
boot.SpringApplication.main() 或 ApplicationStarter.main()
boot.SpringApplication.run()
boot.SpringApplication.refreshContext()
boot.SpringApplication.refresh()
boot.web.servlet.context.ServletWebServerApplicationContext.refresh()
【Spring部分】
context.support.AbstractApplicationContext.refresh()
context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors()
context.support.PostPreprocessorRegistrationDelegate.invokeBeanFactoryPostProcessors()
context.annotation.ConfigurationClassPostProcessor.postProcessBeanFactory()
context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions()
context.annotation.ConfigurationClassParser.parse() (正是上一小结所述接口)
context.annotation.ConfigurationClassParser.parse() 代码中,
this.reader.loadBeanDefinitions(configClasses);将解析获取的configClasses注册为 BeanDefinition
二、源码细节
(SpringBoot) boot.autoconfigure.EnableAutoConfiguration注解
1 2 3 4 5 6 7 8 9 10 11 12 | @Target (ElementType.TYPE) @Retention (RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import (AutoConfigurationImportSelector. class ) // 载入selector,识别AutoConfigutaion类并import public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration" ; // @interface的参数,以方法形式声明 Class<?>[] exclude() default {}; String[] excludeName() default {}; } |
@EnableAutoConfiguration注解有两个参数和一个属性变量。
注入了一个AutoConfigurationImportSelector类实例,看起来应该是用于筛选AutoConfiguration的Import的。
@AutoConfigurationPackage待以后另行分析。
(SpringBoot) boot.autoconfigure.AutoConfigurationImportSelector类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { //...... @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { // 如果AutoConfiguration没开,返回{} if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } // 将spring-autoconfigure-metadata.properties的键值对配置载入到PropertiesAutoConfigurationMetadata对象中并返回 AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader .loadMetadata( this .beanClassLoader); // 基于各种配置计算需要import的configuration和exclusion AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } // 判断AudoConfiguration是否开启 protected boolean isEnabled(AnnotationMetadata metadata) { if (getClass() == AutoConfigurationImportSelector. class ) { // 如果配置文件中有"spring.boot.enableautoconfiguration",返回该字段的值;否则返回true return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean. class , true ); } return true ; } protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } // 获取注解的属性值 AnnotationAttributes attributes = getAttributes(annotationMetadata); // 从META-INF/spring.factories文件中获取EnableAutoConfiguration所对应的configurations List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); // 去重,List转Set再转List configurations = removeDuplicates(configurations); // 从注解的exclude/excludeName属性中获取排除项 Set<String> exclusions = getExclusions(annotationMetadata, attributes); // 对于不属于AutoConfiguration的exclude报错 checkExcludedClasses(configurations, exclusions); // 从configurations去除exclusions configurations.removeAll(exclusions); // 由所有AutoConfigurationImportFilter类的实例再进行一次筛选,去 configurations = filter(configurations, autoConfigurationMetadata); // 把AutoConfigurationImportEvent绑定在所有AutoConfigurationImportListener子类实例上 fireAutoConfigurationImportEvents(configurations, exclusions); // 返回(configurations, exclusions)组 return new AutoConfigurationEntry(configurations, exclusions); } // ...... } |
可见selectImports()是AutoConfigurationImportSelector的核心函数,其核心功能就是获取spring.factories中EnableAutoConfiguration所对应的Configuration类列表,由@EnableAutoConfiguration注解中的exclude/excludeName参数筛选一遍,再由AutoConfigurationImportFilter类所有实例筛选一遍,得到最终的用于Import的configuration和exclusion。
该函数是被谁调用的呢?在org.springframework.context.annotation.ConfigurationClassParser类中被processImports()调用,而processImports()函数被doProcessConfigurationClass()调用。下面从doProcessConfigurationClass() 看起。
(Spring) context.annotation.ConfigurationClassParser.doProcessConfigurationClass()方法
其中,configClass是一个ConfigurationClass实例,记录了bean name(返回的bean名)和meta data(配置数据);sourceClass是简单封装后的有注解的类,主要方便对类的注解的使用,初始值是封装过的configClass。
doProcessConfigurationClass() 对ConfigurationClass进行了各种配置,包括process @ComponentScan, process @Bean, process @Import等等。如果该SourceClass有父类,返回父类,否则返回null。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | @Nullable protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { // ...... // Process any @Import annotations processImports(configClass, sourceClass, getImports(sourceClass), true ); // ...... // Process superclass, if any if (sourceClass.getMetadata().hasSuperClass()) { String superclass = sourceClass.getMetadata().getSuperClassName(); if (superclass != null && !superclass.startsWith( "java" ) && ! this .knownSuperclasses.containsKey(superclass)) { this .knownSuperclasses.put(superclass, configClass); // Superclass found, return its annotation metadata and recurse return sourceClass.getSuperClass(); } } // No superclass -> processing is complete return null ; } |
其中,processImports()方法的第三个参数中,getImports()方法嵌套的遍历了sourceClass的注解,搜集所有@Import注解的值,即被Import的类名集合。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException { Set<SourceClass> imports = new LinkedHashSet<>(); Set<SourceClass> visited = new LinkedHashSet<>(); collectImports(sourceClass, imports, visited); return imports; } private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited) throws IOException { // 如果是头一次添加 if (visited.add(sourceClass)) { for (SourceClass annotation : sourceClass.getAnnotations()) { String annName = annotation.getMetadata().getClassName(); // 当前注解的类名是否是Import if (!annName.equals(Import. class .getName())) { // 嵌套遍历被Import的类 collectImports(annotation, imports, visited); } } // 增加Import注解的值,即被Import的类名 imports.addAll(sourceClass.getAnnotationAttributes(Import. class .getName(), "value" )); } } |
(Spring) context.annotation.ConfigurationClassParser.processImports()方法
processImports() 的第一个参数configClass,是上层函数processConfigurationClass()的唯一参数,即被处理的Configuration类。第二个参数currentSourceClass是configClass的SourceClass类封装。第三个参数是嵌套遍历出的所有需要被Import的类。第四个参数指定是否检查循环import。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, boolean checkForCircularImports) { // ...... for (SourceClass candidate : importCandidates) { // 如果candidate(即被@Import的类)是ImportSelector的子类 if (candidate.isAssignable(ImportSelector. class )) { // Candidate class is an ImportSelector -> delegate to it to determine imports Class<?> candidateClass = candidate.loadClass(); // 生成candidate class(一个ImportSelector子类)的实例 ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector. class ); // 将ImportSelector子类实例挂载为对应功能的Aware类(用于消息通知?) ParserStrategyUtils.invokeAwareMethods( selector, this .environment, this .resourceLoader, this .registry); // DeferredImportSelector是一种特殊的ImportSelector,这里单独处理 if (selector instanceof DeferredImportSelector) { // 挂到deferredImportSelectors列表上 this .deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector); } else { // 筛选符合要求的@Import的名字 String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); // 转换成名字对应的类的集合 Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames); // 嵌套判断被@Import的类是不是还有@Import注解 processImports(configClass, currentSourceClass, importSourceClasses, false ); } } // ...... } // ...... } |
(Spring) context.annotation.ConfigurationClassParser.DefferedImportSelectorHandler私有类
deferredImportSelectors已被初始化为ArrayList<>(),因此全部走else分支。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | private class DeferredImportSelectorHandler { @Nullable private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>(); public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) { DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder( configClass, importSelector); // 一个封装后的pair // deferredImportSelectors被初始化为ArrayList<>(),所以if分支永远不会执行到? if ( this .deferredImportSelectors == null ) { DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler(); handler.register(holder); // 注册到DeferredImportSelectorGroupingHandler.configurationClasses中 handler.processGroupImports(); // -> processImports() } else { // 所有的DeferredImportSelector类实例都挂到deferredImportSelectors列表上 this .deferredImportSelectors.add(holder); } } // ...... } |
那么deferredImportSelectors上挂载的DefferedImportSelector类是何时处理的呢?
doProcessConfigurationClass() 方法被processConfigurationClass() 调用,而processConfigurationClass() 被parse() 调用。可以看到在处理完所有的普通ImportSelector类后,即嵌套载入需要的被Import的类的实例之后,再统一处理DefferedImportSelector类。
(Spring) context.annotation.ConfigurationClassParser.processConfigurationClass() 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 | protected void processConfigurationClass(ConfigurationClass configClass) throws IOException { // ... // Recursively process the configuration class and its superclass hierarchy. SourceClass sourceClass = asSourceClass(configClass); do { // 如果sourceClass有父类会返回父类,否则返回null sourceClass = doProcessConfigurationClass(configClass, sourceClass); } while (sourceClass != null ); this .configurationClasses.put(configClass, configClass); } |
(Spring) context.annotation.ConfigurationClassParser.parse() 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | public void parse(Set<BeanDefinitionHolder> configCandidates) { // 处理所有的ImportSelector类,其中DeferredImportSelector类只挂在deferredImportSelectorHandler列表上不处理,其他均处理,即嵌套遍历被Import的类 for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder.getBeanDefinition(); try { if (bd instanceof AnnotatedBeanDefinition) { parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName()); } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) { parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName()); } else { parse(bd.getBeanClassName(), holder.getBeanName()); } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to parse configuration class [" + bd.getBeanClassName() + "]" , ex); } } // 处理deferredImportSelectorHandler上挂着的DeferredImportSelector类 this .deferredImportSelectorHandler.process(); } protected final void parse( @Nullable String className, String beanName) throws IOException { Assert.notNull(className, "No bean class name for configuration class bean definition" ); MetadataReader reader = this .metadataReaderFactory.getMetadataReader(className); processConfigurationClass( new ConfigurationClass(reader, beanName)); } protected final void parse(Class<?> clazz, String beanName) throws IOException { processConfigurationClass( new ConfigurationClass(clazz, beanName)); } protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException { processConfigurationClass( new ConfigurationClass(metadata, beanName)); } |
再来看看DeferredImportSelector实例是如何被处理的。
(Spring) context.annotation.ConfigurationClassParser.DefferedImportSelectorHandler私有类
和普通ConfigurationClass一样,DefferedImportSelector最后也是先注册到列表中,再依次嵌套处理,只不过在import前多了一个根据order排序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // 对@Order(...)进行排序 private static final Comparator<DeferredImportSelectorHolder> DEFERRED_IMPORT_COMPARATOR = (o1, o2) -> AnnotationAwareOrderComparator.INSTANCE.compare(o1.getImportSelector(), o2.getImportSelector()); private class DeferredImportSelectorHandler { // ... public void process() { List<DeferredImportSelectorHolder> deferredImports = this .deferredImportSelectors; this .deferredImportSelectors = null ; try { if (deferredImports != null ) { DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler(); deferredImports.sort(DEFERRED_IMPORT_COMPARATOR); // 添加到handler的configurationClasses列表中 deferredImports.forEach(handler::register); // 对handler中每个grouping的每个configClass,调用processImports() handler.processGroupImports(); } } finally { this .deferredImportSelectors = new ArrayList<>(); } } } |
DONE.