您好,登錄后才能下訂單哦!
這篇文章主要講解了“Spring Boot配置類加載流程示例”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Spring Boot配置類加載流程示例”吧!
本文基于Spring Boot 1.4.1.RELEASE版本
啟動代碼如下
@SpringBootApplication public class SampleApplication { public static void main(String[] args) throws Exception { SpringApplication.run(SampleApplication.class, args); } }
然后開始分析流程,由于Spring細節眾多,所以我們只關注重點就行了,不然容易迷失在其中
//ConfigurationClassPostProcessor.java //第273行 public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { List<BeanDefinitionHolder> configCandidates = new ArrayList<BeanDefinitionHolder>(); String[] candidateNames = registry.getBeanDefinitionNames(); //遍歷已經注冊的所有bean for (String beanName : candidateNames) { BeanDefinition beanDef = registry.getBeanDefinition(beanName); //判斷這個bean是不是已經被加載過的配置類 if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) || ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) { if (logger.isDebugEnabled()) { logger.debug("Bean definition has already been processed as a configuration class: " + beanDef); } } //如果沒加載過,判斷一下是不是配置類 //這個判斷邏輯很簡單,有興趣的朋友可以自己了解一下 //因為是工具類,其實不看也不影響大局,注意這里check完之后,上邊的校驗就是true了 else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) { configCandidates.add(new BeanDefinitionHolder(beanDef, beanName)); } } if (configCandidates.isEmpty()) { return; } //這段代碼的功能是將配置類按照Order排序,但其實沒有用, //因為此時的configCandidates列表中只有一個元素,就是SampleApplication Collections.sort(configCandidates, new Comparator<BeanDefinitionHolder>() { @Override public int compare(BeanDefinitionHolder bd1, BeanDefinitionHolder bd2) { int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition()); int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition()); return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0; } }); //省略部分代碼 //這里就是配置解析的關鍵 parser.parse(candidates); //省略部分代碼 }
接下來看ConfigurationClassParser這個類
//ConfigurationClassParser.java //第166行 public void parse(Set<BeanDefinitionHolder> configCandidates) { this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>(); //遍歷所有的配置類,根據類型調用不同的parse方法 //這里分成的三種類型各代表什么,暫時不太清楚 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); } } //省略部分代碼 }
不同的parse方法會將各種參數組裝成ConfigurationClass對象,傳給processConfigurationClass()
//ConfigurationClassParser.java //第208行 protected void processConfigurationClass(ConfigurationClass configClass) throws IOException { //判斷當前要解析的bean是否符合解析的條件 if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) { return; } ConfigurationClass existingClass = this.configurationClasses.get(configClass); if (existingClass != null) { if (configClass.isImported()) { if (existingClass.isImported()) { existingClass.mergeImportedBy(configClass); } return; } else { this.configurationClasses.remove(configClass); for (Iterator<ConfigurationClass> it = this.knownSuperclasses.values().iterator(); it.hasNext(); ) { if (configClass.equals(it.next())) { it.remove(); } } } } //省略部分代碼 } //ConditionEvaluator.java //第73行 //AnnotatedTypeMetadata:類上的注解信息 //ConfigurationPhase:PARSE_CONFIGURATION-在解析配置時校驗;REGISTER_BEAN-在注冊bean時校驗 public boolean shouldSkip(AnnotatedTypeMetadata metadata, ConfigurationPhase phase) { //如果沒有配置條件,直接返回 if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) { return false; } //如果不指定phase,配置類使用PARSE_CONFIGURATION,其他使用REGISTER_BEAN if (phase == null) { if (metadata instanceof AnnotationMetadata && ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) { return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION); } return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN); } //獲取Condition并判斷條件 List<Condition> conditions = new ArrayList<Condition>(); for (String[] conditionClasses : getConditionClasses(metadata)) { for (String conditionClass : conditionClasses) { Condition condition = getCondition(conditionClass, this.context.getClassLoader()); conditions.add(condition); } } AnnotationAwareOrderComparator.sort(conditions); for (Condition condition : conditions) { ConfigurationPhase requiredPhase = null; if (condition instanceof ConfigurationCondition) { requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase(); } if (requiredPhase == null || requiredPhase == phase) { if (!condition.matches(this.context, metadata)) { return true; } } } return false; }
開始解析配置類之前,會先判斷當前類是否符合條件以及是否已經解析過,然后才會進入解析流程
//ConfigurationClassParser.java //第208行 protected void processConfigurationClass(ConfigurationClass configClass) throws IOException { //省略部分代碼 //遞歸處理配置類和它的父類 SourceClass sourceClass = asSourceClass(configClass); do { sourceClass = doProcessConfigurationClass(configClass, sourceClass); } while (sourceClass != null); this.configurationClasses.put(configClass, configClass); }
解析的流程有點多,我們分段處理
1、處理嵌套(內部)的配置類
//ConfigurationClassParser.java //第252行 protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { //先遞歸處理嵌套(內部)的配置類 processMemberClasses(configClass, sourceClass); //省略部分代碼 } //ConfigurationClassParser.java //第326行 private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { for (SourceClass memberClass : sourceClass.getMemberClasses()) { if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) && !memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) { if (this.importStack.contains(configClass)) { this.problemReporter.error(new CircularImportProblem(configClass, this.importStack)); } else { this.importStack.push(configClass); try { //回到最開始解析的地方,遞歸處理 processConfigurationClass(memberClass.asConfigClass(configClass)); } finally { this.importStack.pop(); } } } } }
2、處理@PropertySource注解
//ConfigurationClassParser.java //第252行 protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { //省略部分代碼 for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) { if (this.environment instanceof ConfigurableEnvironment) { //解析properties配置文件并放到Spring環境中 processPropertySource(propertySource); } else { logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() + "]. Reason: Environment must implement ConfigurableEnvironment"); } } //省略部分代碼 }
3、處理@ComponentScan注解
//ConfigurationClassParser.java //第252行 protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { //省略部分代碼 //獲取所有的@ComponentScan注解 Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class); if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) { for (AnnotationAttributes componentScan : componentScans) { //根據@ComponentScan注解獲取bean Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); for (BeanDefinitionHolder holder : scannedBeanDefinitions) { //判斷掃描的bean中是否有配置類,有的話繼續遞歸解析 if (ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(), this.metadataReaderFactory)) { parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName()); } } } } //省略部分代碼 }
4、處理@Import注解,@Import作用是導入Java配置類
Spring Boot的@EnableAutoConfiguration注解也會在這里處理,所以如果你的自動配置類被@ComponentScan注解掃描到了,只會被當做普通的配置類,自動配置排序相關的注解(@AutoConfigureAfter等等)都是無效的
//ConfigurationClassParser.java //第252行 protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { //省略部分代碼 processImports(configClass, sourceClass, getImports(sourceClass), true); //省略部分代碼 } //ConfigurationClassParser.java //第441行 private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException { Set<SourceClass> imports = new LinkedHashSet<SourceClass>(); Set<SourceClass> visited = new LinkedHashSet<SourceClass>(); collectImports(sourceClass, imports, visited); return imports; } //ConfigurationClassParser.java //第461行 private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited) throws IOException { //visited保存所有處理過的類,防止重復處理 if (visited.add(sourceClass)) { //取sourceClass上的所有@Import注解,包括其他注解中的@Import注解 for (SourceClass annotation : sourceClass.getAnnotations()) { String annName = annotation.getMetadata().getClassName(); //這里不太懂為啥判斷java開頭 if (!annName.startsWith("java") && !annName.equals(Import.class.getName())) { collectImports(annotation, imports, visited); } } imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value")); } } //ConfigurationClassParser.java //第494行 private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException { if (importCandidates.isEmpty()) { return; } //校驗是否存在循環依賴 if (checkForCircularImports && isChainedImportOnStack(configClass)) { this.problemReporter.error(new CircularImportProblem(configClass, this.importStack)); } else { this.importStack.push(configClass); try { for (SourceClass candidate : importCandidates) { if (candidate.isAssignable(ImportSelector.class)) { Class<?> candidateClass = candidate.loadClass(); ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class); ParserStrategyUtils.invokeAwareMethods( selector, this.environment, this.resourceLoader, this.registry); //如果是DeferredImportSelector接口,先暫存起來,在ConfigurationClassParser.parse(Set<BeanDefinitionHolder>)方法的最后處理(即其他配置類加載完之后) if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) { this.deferredImportSelectors.add( new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector)); } //普通的ImportSelector接口直接遞歸處理 else { String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames); processImports(configClass, currentSourceClass, importSourceClasses, false); } } //ImportBeanDefinitionRegistrar接口在ConfigurationClassParser.parse(Set<BeanDefinitionHolder>)方法執行完畢后處理(即所有配置類加載完之后) else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { Class<?> candidateClass = candidate.loadClass(); ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class); ParserStrategyUtils.invokeAwareMethods( registrar, this.environment, this.resourceLoader, this.registry); configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } //既不是ImportSelector也不是ImportBeanDefinitionRegistrar,當做普通的@Configuration類處理 else { this.importStack.registerImport( currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); processConfigurationClass(candidate.asConfigClass(configClass)); } } } 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(); } } }
5、處理@ImportResource注解,@ImportResource作用是導入XML配置
//ConfigurationClassParser.java //第252行 protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { //省略部分代碼 if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) { AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class); String[] resources = importResource.getStringArray("locations"); Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader"); for (String resource : resources) { String resolvedResource = this.environment.resolveRequiredPlaceholders(resource); //xml配置文件跟ImportBeanDefinitionRegistrar接口一樣,也會暫存起來 //在ConfigurationClassParser.parse(Set<BeanDefinitionHolder>)方法執行完畢后處理(即所有配置類加載完之后) configClass.addImportedResource(resolvedResource, readerClass); } } //省略部分代碼 }
6、處理單獨的@Bean方法
//ConfigurationClassParser.java //第252行 protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { //省略部分代碼 Set<MethodMetadata> beanMethods = sourceClass.getMetadata().getAnnotatedMethods(Bean.class.getName()); for (MethodMetadata methodMetadata : beanMethods) { //暫存起來,在ConfigurationClassParser.parse(Set<BeanDefinitionHolder>)方法執行完畢后處理(即所有配置類加載完之后) configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); } //省略部分代碼 }
7、處理實現的接口中的default方法
//ConfigurationClassParser.java //第252行 protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { //省略部分代碼 processInterfaces(configClass, sourceClass); //省略部分代碼 } //ConfigurationClassParser.java //第349行 private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { for (SourceClass ifc : sourceClass.getInterfaces()) { Set<MethodMetadata> beanMethods = ifc.getMetadata().getAnnotatedMethods(Bean.class.getName()); for (MethodMetadata methodMetadata : beanMethods) { if (!methodMetadata.isAbstract()) { //暫存起來,在ConfigurationClassParser.parse(Set<BeanDefinitionHolder>)方法執行完畢后處理(即所有配置類加載完之后) configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); } } //遞歸處理 processInterfaces(configClass, ifc); } }
8、處理父類中的方法
//ConfigurationClassParser.java //第252行 protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { //省略部分代碼 if (sourceClass.getMetadata().hasSuperClass()) { String superclass = sourceClass.getMetadata().getSuperClassName(); if (!superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) { this.knownSuperclasses.put(superclass, configClass); //如果存在符合條件的父類,返回它,然后繼續解析 //doProcessConfigurationClass方法被調用的地方是一個while循環,只要不為null就會一直調用 return sourceClass.getSuperClass(); } } //省略部分代碼 }
9、處理之前暫存的DeferredImportSelector接口
//ConfigurationClassParser.java //第166行 public void parse(Set<BeanDefinitionHolder> configCandidates) { //省略部分代碼 processDeferredImportSelectors(); } //ConfigurationClassParser.java //第473行 private void processDeferredImportSelectors() { List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors; this.deferredImportSelectors = null; Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR); for (DeferredImportSelectorHolder deferredImport : deferredImports) { ConfigurationClass configClass = deferredImport.getConfigurationClass(); try { String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata()); processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false); } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", ex); } } }
10、加載xml配置文件、ImportBeanDefinitionRegistrar接口實現類以及標注了@Bean的方法
//ConfigurationClassPostProcessor.java //第273行 public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { //省略部分代碼 this.reader.loadBeanDefinitions(configClasses); //省略部分代碼 } //ConfigurationClassBeanDefinitionReader.java //第113行 public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) { TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator(); for (ConfigurationClass configClass : configurationModel) { loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator); } } //ConfigurationClassBeanDefinitionReader.java //第124行 private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) { //省略部分代碼 if (configClass.isImported()) { //將配置類自己也注冊成一個bean registerBeanDefinitionForImportedConfigurationClass(configClass); } for (BeanMethod beanMethod : configClass.getBeanMethods()) { //將標記了@Bean的方法加載成bean loadBeanDefinitionsForBeanMethod(beanMethod); } //加載XML配置文件 loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); //加載ImportBeanDefinitionRegistrar接口的實現 loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); }
感謝各位的閱讀,以上就是“Spring Boot配置類加載流程示例”的內容了,經過本文的學習后,相信大家對Spring Boot配置類加載流程示例這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。