一、Spring處理配置類大致過程
回憶一下Spring處理配置類的大致過程【ConfigurationClassPostProcessor】
【BeanFactoryPostProcessor -> BeanDefinitionRegistryPostProcessor】 ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry -> ConfigurationClassPostProcessor#processConfigBeanDefinitions -> ConfigurationClassParser#parse(Set<BeanDefinitionHolder>) 開始解析配置傳入的配置類 ConfigurationClassParser#parse(Set<BeanDefinitionHolder>) - #parse(AnnotationMetadata, String) [最后調用 deferredImportSelectorHandler.process] - #processConfigurationClass [@Import導入的非三個特殊接口的類遞歸調用此方法處理], [調用此方法處理的配置類都放入 configurationClasses 字段] - #doProcessConfigurationClass - #processImports @Component掃描出來的遞歸調用ConfigurationClassParser#parse(String, String)處理 - #processConfigurationClass 進而調用它, 回到上面的步驟
二、@Import大致處理過程
直接看@Import的處理過程
protected final SourceClass doProcessConfigurationClass( ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter) throws IOException { // 使用了@Component注解, ... // Process any @PropertySource annotations, .... // Process any @ComponentScan annotations, ... // Process any 【@Import】 annotations processImports(configClass, sourceClass, getImports(sourceClass), filter, true); // Process any @ImportResource annotations, ... // Process individual @Bean methods // 處理@Bean,獲取所有 @Bean 方法,還沒有到代理的邏輯, .... // 處理繼承的接口中的使用@Bean修飾的deafult方法 processInterfaces(configClass, sourceClass); // Process superclass, if any, ... // 沒有父類 return null; } private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter, boolean checkForCircularImports) { // 沒有Import任何東西,則僅表示此類是一個配置類 if (importCandidates.isEmpty()) { return; } // 循環注入的檢查 if (checkForCircularImports && isChainedImportOnStack(configClass)) { // 報錯 this.problemReporter.error(new CircularImportProblem(configClass, this.importStack)); } else { // importStack 好像是整個解析過程中全局的, importStack 干什么的呢 this.importStack.push(configClass); try { // 遍歷所有被@Import引入的類 for (SourceClass candidate : importCandidates) { // 如果繼承了【ImportSelector】接口 if (candidate.isAssignable(ImportSelector.class)) { // Candidate class is an ImportSelector -> delegate to it to determine imports // 讓這個被Import引入的類決定實際引入那些類 Class<?> candidateClass = candidate.loadClass(); // 實例化 ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class, this.environment, this.resourceLoader, this.registry); Predicate<String> selectorFilter = selector.getExclusionFilter(); if (selectorFilter != null) { exclusionFilter = exclusionFilter.or(selectorFilter); } // 如果是繼承了 DeferredImportSelector 接口 if (selector instanceof DeferredImportSelector) { // 延遲引入,在所有的@Configuration處理完畢后處理,在作為@Conditional條件@Import時特別有用 // 這個應該不可以繼續@Import this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector); } else { // 返回的是字符串全類名 String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter); // 被當作直接@Import的數組再處理,也即可以繼續@Import processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false); } } // 如果繼承ImportBeanDefinitionRegistrar接口,主要是作為在處理@Configuration的過程中添加BD,需要在BD級別自定義一個Bean時有用 else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { // Candidate class is an ImportBeanDefinitionRegistrar -> // delegate to it to register additional bean definitions // 由@Import的實例自行定義BD,上面的兩個都是由Spring幫助定義BD Class<?> candidateClass = candidate.loadClass(); ImportBeanDefinitionRegistrar registrar = ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class, this.environment, this.resourceLoader, this.registry); // 沒有注入BD,什么時候調用 // 放入了ConfigClass中 configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } else { // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> // process it as an @Configuration class // 其他被@Import的類,被當作配置類進行處理 // 注意這里和掃描出來的有區別,掃描出來的是立即注入BD,然后如果是配置類再解析 // 而@Import暫時不注入,當作配置類解析,但是 processConfigurationClass 調用后被放在字段 configurationClasses 中 this.importStack.registerImport( currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter); } } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", ex); } finally { this.importStack.pop(); } } }
@Import區分了三種類
- 繼承了ImportSelector接口的類,直接實例化這個類,調用selectImports將返回的類全限定名數組當做配置類處理,注意這個類不被注入容器
- 繼承了DeferredImportSelector接口(ImportSelector子接口)的類,暫時未處理,可以看到后面處理后也是講返回的類全部調用processImports當做被直接@Import的處理
- 繼承了ImportBeanDefinitionRegistrar接口的類,暫時未處理,【用於自定義BD注入】
- 普通類,當做配置類進行解析
三、DeferredImportSelector接口處理
看DeferredImportSelector接口的處理
注意前面processImports時已經將@Import進入的DeferredImportSelector接口的類this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector)添加了
// deferredImportSelectorHandler 為 ConfigurationClassParser 的全局字段 // 實際上就是存儲起來, 暫時不調用 this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector); private class DeferredImportSelectorHandler { private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>(); // @Import 遇到 DeferredImportSelectorHolder 先不處理, 調用它存儲起來 public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) { // 包裝 configClass 和 importSelector 實例, 前者配置類, 后者被配置類 @Import 的 DeferredImportSelector DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector); // process后才為null,process后的其他直接進行處理 // 什么時候會為 null ? 為 null 的時候應該是見一個立即處理一個, 否則存儲起來等待一起被調用處理 if (this.deferredImportSelectors == null) { DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler(); handler.register(holder); handler.processGroupImports(); } else { // List#add this.deferredImportSelectors.add(holder); } } }
DeferredImportSelectorHolder的定義較為簡單,僅封裝兩個字段,相當於Pair,就不列出來了
接着等待被處理,什么時候處理呢?看最開始列出的流程,在剛進入的第一個方法parse最后處理,此時parse的這些配置類已被處理完畢,【這些配置類僅是ConfigurationClassPostProcessor第一次找到的所有配置類,待續】
ConfigurationClassPostProcessor#processConfigBeanDefinitions --> public void ConfigurationClassParser.parse(Set<BeanDefinitionHolder> configCandidates) { // 內部都是配置類,都需要進行解析 for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder.getBeanDefinition(); try { // 注解BD,只看這個即可 if (bd instanceof AnnotatedBeanDefinition) { parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName()); } // ... } } // 這里處理 DeferredImportSelector this.deferredImportSelectorHandler.process(); }
DeferredImportSelectorHandler的其余代碼,前面注冊的handle已列出
class ConfigurationClassParser{ private class DeferredImportSelectorHandler { @Nullable private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>(); public void process() { // 所有的 DeferredImportSelector List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors; // 清空, handler的那個null判斷處理難道是防止多線程問題??? this.deferredImportSelectors = null; try { if (deferredImports != null) { DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler(); // DeferredImportSelectorHolder 排序 deferredImports.sort(DEFERRED_IMPORT_COMPARATOR); // 遍歷, 調用 DeferredImportSelectorGroupingHandler#register 處理 // 注冊, 對每一個進行注冊 deferredImports.forEach(handler::register); // 實際處理, 批量處理 handler.processGroupImports(); } } finally { this.deferredImportSelectors = new ArrayList<>(); } } } private class DeferredImportSelectorGroupingHandler { /** * 鍵 DeferredImportSelector.Group(可能返回null, null則后面) 或 DeferredImportSelector * 值:DeferredImportSelectorGrouping */ private final Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>(); private final Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>(); // 處理 DeferredImportSelector // 這里僅注冊 public void register(DeferredImportSelectorHolder deferredImport) { // DeferredImportSelectorHolder#getImportSelector 得到 DeferredImportSelectorHolder // 然后 DeferredImportSelectorHolder#getImportGroup, 注意是一個 Class Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup(); // 鍵: DeferredImportSelector.Group 或 為null時使用 DeferredImportSelector // 值: DeferredImportSelectorGrouping DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent( (group != null ? group : deferredImport), // createGroup 創建Group實現類對象並對部分Aware接口進行了回調, 當為null使用 DefaultDeferredImportSelectorGroup key -> new DeferredImportSelectorGrouping(createGroup(group))); // 所有 DeferredImportSelectorHolder // grouping 然后添加 DeferredImportSelectorHolder 實例, 可綁定多個 // 相當於 Map<Group, List> grouping.add(deferredImport); // 所有configuration this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getConfigurationClass()); } // 實際處理 public void processGroupImports() { // 相當於 grouping 為一個 List<DeferredImportSelectorGrouping>, 每個DeferredImportSelectorGrouping含多個Group實例 for (DeferredImportSelectorGrouping grouping : this.groupings.values()) { Predicate<String> exclusionFilter = grouping.getCandidateFilter(); // DeferredImportSelectorGrouping#getImports 會使用一個 Group 實例對多個 DeferredImportSelector 進行處理 // -- 先 forEach -> Group#process(DeferredImportSelector) 一般對每一個DeferredImportSelector能得到此Selector要注入的信息, Group會自己緩存起來 // -- 再 Group#selectImports 總的處理, 返回 Iterable<Entry>, Entry保存着要導入的類和導入此類的配置類的注解信息 grouping.getImports().forEach(entry -> { // 對每一個 Entry 進行處理 // 得到配置類實例 ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata()); try { // !!! 再次processImports, 也就是把要注入的這個類當做 configurationClass 使用 @Import 注入時處理 @Import // 因此還會對這個注入的類進行 @Import 接口處理、配置處理等等 // 不過此時的這個被導入的類使用 DeferredImportSelector、ImportBeanDefinitionRegistrar 接口還有作用嗎 // 倒是可以導入ImportSelector接口的和其他類型配置類(因為會被當做配置類解析一遍) processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter), Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)), exclusionFilter, false); } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to process import candidates for configuration class [" + configurationClass.getMetadata().getClassName() + "]", ex); } }); } } /** * 創建對象,對部分Aware接口進行了回調,應該是還沒到Bean生命周期處理周期就需要使用到 */ private Group createGroup(@Nullable Class<? extends Group> type) { Class<? extends Group> effectiveType = (type != null ? type : DefaultDeferredImportSelectorGroup.class); return ParserStrategyUtils.instantiateClass(effectiveType, Group.class, ConfigurationClassParser.this.environment, ConfigurationClassParser.this.resourceLoader, ConfigurationClassParser.this.registry); } } }
- 一般來說在ConfigurationClassParser#parse的結尾調用deferredImportSelectorHandler.process統一處理此次解析得到的所有DeferredImportSelector
- 在處理@Import過程中區分導入的類是否繼承接口,繼承了則將其通過this.deferredImportSelectorHandler.handle添加進入字段deferredImportSelectorHandler中,可認為其是一個List
- 注意:上面的添加是添加的實例,在實例化后會回調部分Aware接口
- DeferredImportSelectorHandler#handle接受導入這個類的配置類Class和被導入這個類,封裝為DeferredImportSelectorHolder,添加進入List中
- DeferredImportSelectorHandler#process處理
- 新建一個DeferredImportSelectorGroupingHandler類,將所有DeferredImportSelectorHolder注冊進入其中
- 注冊大概干了什么呢?DeferredImportSelectorGroupingHandler可看做一個Map<Group, List<DeferredImportSelectorHolder>>,會調用DeferredImportSelector實例獲取處理它的Group類型,並實例化,Group對象作為k,DeferredImportSelectorHolder實例作為v
- 全部注冊后就是批量處理了,因為全部注入了,只需調用DeferredImportSelectorGroupingHandler#processGroupImports
- 處理又干了什么呢?遍歷Group並處理能處理的DeferredImportSelector實例列表
- Group#process會處理DeferredImportSelector實例得到它要注入的類,並緩存
- 當所有能處理的處理完畢,Group#selectImports得到所有當前Group處理的要注入的類列表
- 將這個列表processImport,也就是當做被配置類@Import解析一遍
- 注意
- 被注入的數據和直接被@Import差不多,不過延遲注入了,基本上大多數和啟動類相關Bean都被解析了才會注入BD,也和ImportSelector接口的差不多,不過延遲解析了
四、SpringBoot自動配置原理
自動配置 @EnableAutoConfiguration
@Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { }
@Import導入了AutoConfigurationImportSelector這個類,而這個類是一個DeferredImportSelector實現類
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {}
可以看到他實現了各種接口,在@Import處理實例化這個類時,會調用部分Aware注入一些已有的實例
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {} // 返回處理當前 DeferredImportSelector 的 Group 類型 @Override public Class<? extends Group> getImportGroup() { return AutoConfigurationGroup.class; } // AutoConfigurationImportSelector 的內部類 // 也繼承了許多接口, 創建當前 Group 實例時也會回調這些 Aware 接口 private static class AutoConfigurationGroup implements DeferredImportSelector.Group, BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware { private final Map<String, AnnotationMetadata> entries = new LinkedHashMap<>(); private final List<AutoConfigurationEntry> autoConfigurationEntries = new ArrayList<>(); private ClassLoader beanClassLoader; private BeanFactory beanFactory; private ResourceLoader resourceLoader; private AutoConfigurationMetadata autoConfigurationMetadata; // 接口回調 setter // 1. 會先調用 process // --> 會使用一個 Group 實例處理它能處理的一系列 DeferredImportSelector 實例 // --> 每一個 DeferredImportSelector 實例都可以注入數據, 現在還未注入, 僅緩存起來 @Override public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) { // 只處理 AutoConfigurationImportSelector // 說明這個 Group 僅處理這個類型的實例, 其他類型的 DeferredImportSelector 不處理 Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, () -> String.format("Only %s implementations are supported, got %s", AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getName())); // AutoConfigurationEntry 包裝了要注入的自動配置類和排除了的配置類 AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector) .getAutoConfigurationEntry(annotationMetadata); this.autoConfigurationEntries.add(autoConfigurationEntry); // 遍歷需要注入的配置類 for (String importClassName : autoConfigurationEntry.getConfigurations()) { // 配置類全類名 -> 導入此配置類的類的注解信息 this.entries.putIfAbsent(importClassName, annotationMetadata); } // 注意上面只是將要注入的數據緩存在了當前 Group 實例中 } // 2. 調用它, 返回處理了的所有 DeferredImportSelector 實例要注入的數據 @Override public Iterable<Entry> selectImports() { if (this.autoConfigurationEntries.isEmpty()) { return Collections.emptyList(); } // 移除的配置類 Set Set<String> allExclusions = this.autoConfigurationEntries.stream() .map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet()); // 要注入的配置類 Set Set<String> processedConfigurations = this.autoConfigurationEntries.stream() .map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream) .collect(Collectors.toCollection(LinkedHashSet::new)); // emm processedConfigurations.removeAll(allExclusions); // 排序 return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream() .map((importClassName) -> // 導入此配置類的類的注解信息為 + 當前被自動注入的類 new Entry(this.entries.get(importClassName), importClassName)) .collect(Collectors.toList()); } // ... } }