Spring5源码分析容器刷新配置类的嵌套类
上一篇:Spring5 源码分析-容器刷新-解析配置类-主流程
功能说明
在解析给定的配置类时,Spring允许它的嵌套类来配置容器相关行为,可以将修饰到配置类上的所有注解都放到嵌套类上面,启到同样的效果
举例demo
示例:
属性文件:
au1.properties
name=HaViage=33
au.properties
name=Messiage=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());
}
}
配置类:
@Configurationpublic 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