上一篇:Spring5 源碼分析-容器刷新-解析配置類-主流程java
在解析給定的配置類時,Spring容許它的嵌套類來配置容器相關行爲,能夠將修飾到配置類上的全部註解都放到嵌套類上面,啓到一樣的效果spring
示例:源碼分析
屬性文件:測試
au1.propertiesthis
name=HaVi age=33
au.propertiesspa
name=Messi age=30
測試類:.net
public class NestedMain { public static void main(String[] args) { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(NestedConfig.class); NestedUser bean = ac.getBean(NestedUser.class); System.out.println(bean.getName()); } }
配置類: code
@Configuration public class NestedConfig { @ComponentScan("com.jv.spring.nestedclass.scan") @PropertySource("classpath:au.properties") class InnerConfig{ } }
Spring在解析的時候發現配置類(NestedConfig)有嵌套類(InnerConfig),那麼會先解析嵌套類並做出對應的動做執行,最後將com.jv.spring.nestedclass.scan下面全部符合Spring規則的類定義都註冊到容器中,並完成實例化等相關動做。blog
輸出結果:遞歸
上一段文字中提到了「先解析」,意思就是說若是咋們還在NestedConfig上面使用註解再指定一個屬性文件,那麼先前的屬性會被覆蓋嗎?測試一下。。。
修改後的配置類:
@Configuration @PropertySource("classpath:au1.properties") public class NestedConfig { @ComponentScan("com.jv.spring.nestedclass.scan") @PropertySource("classpath:au.properties") class InnerConfig{ } }
輸出結果:
總結:配置類上修飾的註解會晚於嵌套類上面的註解被解析與執行,經過上面的例子也證實了配置類上的@PropertySource會覆蓋嵌套類的@PropertySource指定的屬性。。。不要開心太早,Spring提供的註冊BeanDefinition很是多,他們到底誰先執行等把其餘幾種狀況講完了再統一梳理
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { /** * 首先處理@configuration配置類的嵌套類(嵌套類被@Component @Import @ImportResource @ComponentScan 或者這個類是否有被@Bean修飾的Method), * 若是有則會進行遞歸調用processConfigurationClass()->doProcessConfigurationClass() */ if (configClass.getMetadata().isAnnotated(Component.class.getName())) { // Recursively process any member (nested) classes first processMemberClasses(configClass, sourceClass); }
首先配置類得必須有@Component註解,由於@Configuration是組合註解,裏面包含了@Component,因此知足條件,進入分支,執行processMemberClasses方法
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { Collection<SourceClass> memberClasses = sourceClass.getMemberClasses(); if (!memberClasses.isEmpty()) { List<SourceClass> candidates = new ArrayList<>(memberClasses.size()); for (SourceClass memberClass : memberClasses) { if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) && !memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) { candidates.add(memberClass); } } OrderComparator.sort(candidates); for (SourceClass candidate : candidates) { if (this.importStack.contains(configClass)) { this.problemReporter.error(new CircularImportProblem(configClass, this.importStack)); } else { this.importStack.push(configClass); try { //遞歸調用processConfigurationClass-doProcessConfigurationClass processConfigurationClass(candidate.asConfigClass(configClass)); } finally { this.importStack.pop(); } } } } }
若是有嵌套類,則遞歸調用processConfigurationClass。若是嵌套類裏面還有嵌套類,則繼續遞歸調用。。。