Spring5 源碼分析-容器刷新-配置類的嵌套類

上一篇:Spring5 源碼分析-容器刷新-解析配置類-主流程java

功能說明

在解析給定的配置類時,Spring容許它的嵌套類來配置容器相關行爲,能夠將修飾到配置類上的全部註解都放到嵌套類上面,啓到一樣的效果spring

舉例demo

示例:源碼分析

屬性文件:測試

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。若是嵌套類裏面還有嵌套類,則繼續遞歸調用。。。

下一篇:Spring5 源碼分析-容器刷新-@PropertySource

相關文章
相關標籤/搜索