Spring5源码分析容器刷新配置类的嵌套类

编程

上一篇:Spring5 源码分析-容器刷新-解析配置类-主流程

功能说明

在解析给定的配置类时,Spring允许它的嵌套类来配置容器相关行为,可以将修饰到配置类上的所有注解都放到嵌套类上面,启到同样的效果

举例demo

示例:

属性文件:

au1.properties

name=HaVi

age=33

 au.properties

name=Messi

age=30

测试类:

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());

}

}

配置类: 

@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规则的类定义都注册到容器中,并完成实例化等相关动作。

输出结果:

上一段文字中提到了“先解析”,意思就是说如果咋们还在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

以上是 Spring5源码分析容器刷新配置类的嵌套类 的全部内容, 来源链接: utcz.com/z/510742.html

回到顶部