Aware系列都是用于注入响应的资源,Ordered用于排序。
值得关注的是 DeferredImportSelector,查看其类注释,简要翻译如下:
importselector的变体,在所有@Configuration bean之后运行,可以实现Ordered进行排序。
提供{getImportGroup(),它可以跨不同的选择器提供额外的排序和过滤逻辑。
DeferredImportSelector保证在所有@Configuration加载之后执行,也就说,如果有相关配置类已加载,则可以跳过自动装配类。
DeferredImportSelector是如何保证在@Configuration bean加载之后执行的呢???
带着这个疑问,我查看了ConfigurationClassPostProcessor#processConfigBeanDefinitions
(至于为什么要查看这个方法,请看上一篇 @Enable驱动原理 )
浏览过程如下:
概要逻辑如下:
1. ImportSelector的解析在ConfigurationClassParser#processImports中处理
在其中this.deferredImportSelectorHandler.handle(..)j将DeferredImportSelector放入队列,延后处理。
2. DeferredImportSelector处理逻辑在
ConfigurationClassParser#parse中的this.deferredImportSelectorHandler.process()中。
浏览this.deferredImportSelectorHandler.process()代码;
DeferredImportSelectorGrouping#getImports的代码如下:
private static class DeferredImportSelectorGrouping { private final DeferredImportSelector.Group group; public Iterable<Group.Entry> getImports() { for (DeferredImportSelectorHolder deferredImport : this.deferredImports) { this.group.process(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getImportSelector()); } return this.group.selectImports(); } } }复制代码
这里需要关注的是this.group.process,this.group.selectImports2个方法。
也就是AutoConfigurationImportSelector.AutoConfigurationGroup的process,selectImports就是我们需要关注的核心方法。
public class AutoConfigurationImportSelector { private static class AutoConfigurationGroup{ //省略其他代码 private final Map<String, AnnotationMetadata> entries = new LinkedHashMap<>(); @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(getAutoConfigurationMetadata(), annotationMetadata); this.autoConfigurationEntries.add(autoConfigurationEntry); for (String importClassName : autoConfigurationEntry.getConfigurations()) { this.entries.putIfAbsent(importClassName, annotationMetadata); } } }复制代码
概要逻辑:
1.getAutoConfigurationMetadata() 加载autoConfigurationMetadata,
2.getAutoConfigurationEntry()根据autoConfigurationMetadata获得AutoConfigurationEntry
3.通过AutoConfigurationEntry ,获得要导入的类的名称,存入内部的 autoConfigurationEntries中
public class AutoConfigurationImportSelector { private static class AutoConfigurationGroup{ private AutoConfigurationMetadata getAutoConfigurationMetadata() { if (this.autoConfigurationMetadata == null) { this.autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader); } return this.autoConfigurationMetadata; } } }复制代码
核心就是AutoConfigurationMetadataLoader.loadMetadata 查看其源码如下:
final class AutoConfigurationMetadataLoader { protected static final String PATH = "META-INF/" + "spring-autoconfigure-metadata.properties"; private AutoConfigurationMetadataLoader() { } public static AutoConfigurationMetadata loadMetadata (ClassLoader classLoader) { return loadMetadata(classLoader, PATH); } static AutoConfigurationMetadata loadMetadata (ClassLoader classLoader, String path) { try { Enumeration<URL> 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); } } //省略部分代码 } 复制代码
加载autoConfigurationMetadata,就是读取META-INF/spring-autoconfigure-metadata.properties的配置文件,转换为autoConfigurationMetadata对象。
getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata)的实现如下
public class 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); } }复制代码
概要逻辑:
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; }复制代码
查看 SpringFactoriesLoader源码如下:
public final class SpringFactoriesLoader { //省略部分代码 public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; public static List<String> loadFactoryNames( Class<?> factoryClass, @Nullable ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); return loadSpringFactories(classLoader) .getOrDefault(factoryClassName, Collections.emptyList()); } private static Map<String, List<String>> loadSpringFactories( @Nullable ClassLoader classLoader) { MultiValueMap<String, String> result = cache.get(classLoader); if (result != null) { return result; } try { 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())) { 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); } } } 复制代码
读取指定ClassLoader下的所有的,META-INF/spring.factories资源内容,合并一个key为全类名,Value为实现类名列表的Map,从Map中找到指定的key对应的实现类全类名列表
public class AutoConfigurationImportSelector{ 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#match没有匹配上的过滤掉
查看getAutoConfigurationImportFilters()源码如下:
protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() { return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader); }复制代码
SpringFactoriesLoader.loadFactories(...),调用SpringFactoriesLoader.loadFactoryNames(...)后,将列表中的逐个实例化,排序后返回。
查看spring.factories
AutoConfigurationImportFilter的实现类,有
OnClassCondition类,onBeanCondition,OnWebApplicationCondition等。
OnClassCondition代码大致逻辑如下:
OnClassCondition#match调用了autoConfigurationMetadata.getSet获取当前配置类的ConditionOnClass属性。
举例说明OnClassCondition#getOutcomes
例如:
加载AConfigurationClass,AConfigurationClass的ConditionOnClass=XXX,
如果XXX不在当前classloader下,排除 AConfigurationClass
public class AutoConfigurationImportSelector{ private static class AutoConfigurationGroup{ @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()); } } } } }复制代码
概要逻辑如下 :
排除不必要的项
sortAutoConfigurations排序自动配置项。
public class AutoConfigurationImportSelector{ private static class AutoConfigurationGroup{ private List<String> sortAutoConfigurations(Set<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) { return new AutoConfigurationSorter(getMetadataReaderFactory(), autoConfigurationMetadata) .getInPriorityOrder(configurations); } } } 复制代码
核心在AutoConfigurationSorter#getInPriorityOrder中
class AutoConfigurationSorter { //省略其他代码 public List<String> getInPriorityOrder(Collection<String> classNames) { AutoConfigurationClasses classes = new AutoConfigurationClasses(this.metadataReaderFactory, this.autoConfigurationMetadata, classNames); List<String> orderedClassNames = new ArrayList<>(classNames); // Initially sort alphabetically Collections.sort(orderedClassNames); // Then sort by order orderedClassNames.sort((o1, o2) -> { int i1 = classes.get(o1).getOrder(); int i2 = classes.get(o2).getOrder(); return Integer.compare(i1, i2); }); // Then respect @AutoConfigureBefore @AutoConfigureAfter orderedClassNames = sortByAnnotation(classes, orderedClassNames); return orderedClassNames; } }复制代码
排序规则如下:
按照字母顺序加载,否则先按AutoCOnfigureOrder,再按@AutoConfigureBefore,@AutoConfigureAfter进行排序。
注:
AutoCOnfigurationMetadata(META-INF/spring-autoconfigure-metadata.properties)中包含AutoConfigureOrder,AutoConfigureBefore,AutoConfigureAfter信息
名称 | 注释 |
是否推荐 |
@AutoCOnfigureOrder | 绝对自动装配顺序 | 否 |
@AutoConfigureBefore, @AutoConfigureAfter |
相对自动装配顺序,建议使用name属性 | 是 |
整体流程到这里就看完了,但是自定义配置如何覆盖自动装配的呢?
为了查找自定义配置如何覆盖自动装配,我再次翻阅代码
查看shouldSkip,结合各种Conditional注解进行过滤
@Conditional 是个多个条件注解的元注解,例如:@ConditionalOnMissingBean,@ConditionalOnClass等。
具体逻辑,就不在这里赘述了,如果想查阅,可以查看org.springframework.boot.autoconfigure.condition.OnClassCondition这个类,它是@ConditionalOnClass的逻辑处理类。