ConfigurationClassParser加载bean定义还有一点尾巴
循环解析加载bean定义
上一篇讲了是一次解析加载bean
定义的过程,其实外面是个循环,因为你加载了bean
定义后,可能会有新的配置类的bean
定义,所以也要进行解析和加载bean
,因此是一个循环。我省略了部分代码,把主要的循环流程和判断留下来了。其实就是循环处理新加载进来的配置类的bean
定义,直到没有为止。
do {//开始解析configCandidates元素
parser.parse(candidates);//解析配置类集合
parser.validate();//验证如果要CGLIB代理的话,条件是否满足,比如类不能final,bean注解
this.reader.loadBeanDefinitions(configClasses);//加载bean定义
...
if (registry.getBeanDefinitionCount() > candidateNames.length) {//如果有加载到新的bean定义,再继续加载
...
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {//处理新的
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {//符合配置类要求就添加到candidates
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;//更新候选名字
}
}
while (!candidates.isEmpty());
注册单例importStack
把importStack
注册为单例,为了支持ImportAware
接口扩展,说明已经处理Import
注解过了。
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
清除字节码元数据缓存
有些bean
定义的元数据是通过URL
加载字节码文件解析来的,为了避免每次都去IO
操作,会有元数据的缓存,现在处理完了就要把缓存清除了。
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
BeanDefinitionRegistryPostProcessor后置处理器处理流程
处理一般排序的BeanDefinitionRegistryPostProcessor后置处理器
至此ConfigurationClassPostProcessor
的处理完成了,也就是有优先级PriorityOrdered
的后置处理器处理好了,现在要处理一般顺序Ordered
的处理器了,这段代码跟前面的一样,只是这次是取一般顺序的处理器,执行的是一样的流程,这里还是再次获取BeanDefinitionRegistryPostProcessor
类型的,会把所有的都获取出来,当然包括处理过的,不过没关系,处理过的处理器会放入processedBeans
中,不会再次处理的:
//再次获取没处理过的BeanDefinitionRegistryPostProcessors且实现Ordered接口的来处理,因为可能前面处理后产生新的bean定义
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
//没处理过的,而且是Ordered类型的
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);//更前面一样,排序,合并,处理,清除
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
其实这里也可能是PriorityOrdered类型的,是通过前面解析出来的。比如我们来看这个扩展点。
扩展点实战一
比如创建了一个TestBeanDefinitionRegistryPostProcessorPriorityOrdered
实现了BeanDefinitionRegistryPostProcessor
和Ordered
。
public class TestBeanDefinitionRegistryPostProcessorPriorityOrdered implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
public TestBeanDefinitionRegistryPostProcessorPriorityOrdered(){
System.out.println("TestBeanDefinitionRegistryPostProcessorPriorityOrdered被创建了");
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("MyBeanDefinitionRegistryPostProcessorPriorityOrdered postProcessBeanDefinitionRegistry");
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("MyBeanDefinitionRegistryPostProcessorPriorityOrdered postProcessBeanFactory");
}
//排序的值,越小越前面
@Override
public int getOrder() {
return 1;
}
}
然后配置类里面用bean
注解方法,直接返回这个实例类型,我这里为了方便,其实应该返回接口类型,另外写一个接口类型比较好的。
@Configuration
public class MyConfig {
@Bean
public TestBeanDefinitionRegistryPostProcessorPriorityOrdered myRegistrar(){
return new TestBeanDefinitionRegistryPostProcessorPriorityOrdered();
}
}
执行的结果就是会被创建出来,然后执行postProcessBeanDefinitionRegistry
方法:
注意
这里要注意,这个时候因为要创建TestBeanDefinitionRegistryPostProcessorPriorityOrdered
处理器,所以MyConfig
也会被创建出来,作为单例。
循环处理最后剩下的BeanDefinitionRegistryPostProcessor后置处理器
最后就处理剩下的那些后置处理器,比如我在前面的扩展点再注册bean
定义。
boolean reiterate = true;//是否还有要处理的
while (reiterate) {
reiterate = false;//默认没有了
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {//剩下没处理过的
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;//还有
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
扩展点实战二
还是刚才的TestBeanDefinitionRegistryPostProcessorPriorityOrdered
,我在postProcessBeanDefinitionRegistry里自定义注册了一个bean
定义TestBeanDefinitionRegistryPostProcessor
。
他就会在最后被getBeanNamesForType
找到执行。
public class TestBeanDefinitionRegistryPostProcessorPriorityOrdered implements BeanDefinitionRegistryPostProcessor, PriorityOrdered {
public TestBeanDefinitionRegistryPostProcessorPriorityOrdered() {
System.out.println("TestBeanDefinitionRegistryPostProcessorPriorityOrdered被创建了");
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("MyBeanDefinitionRegistryPostProcessorPriorityOrdered postProcessBeanDefinitionRegistry");
AnnotatedBeanDefinition genericBeanDefinition=new AnnotatedGenericBeanDefinition(TestBeanDefinitionRegistryPostProcessor.class);
registry.registerBeanDefinition("TestBeanDefinitionRegistryPostProcessor",genericBeanDefinition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("MyBeanDefinitionRegistryPostProcessorPriorityOrdered postProcessBeanFactory");
}
//排序的值,越小越前面
@Override
public int getOrder() {
return 1;
}
}
TestBeanDefinitionRegistryPostProcessor
也是BeanDefinitionRegistryPostProcessor
类型的,扩展方法里又注册了一个UserDaoImple
。
public class TestBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("MyBeanDefinitionRegistryPostProcessor postProcessBeanDefinitionRegistry");
registry.registerBeanDefinition("UserDaoImple",new AnnotatedGenericBeanDefinition(UserDaoImple.class));
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("MyBeanDefinitionRegistryPostProcessor postProcessBeanFactory");
}
}
结果:
而且在里面又注册了一个UserDaoImple
:
至此,所有实现的BeanDefinitionRegistryPostProcessor
接口的处理器都处理完成了。
我们的自定义扩展顺序可以看这里:
扩展点顺序
ConfigurationClassPostProcessor
处理MyConfig
,MyConfig
定义了TestBeanDefinitionRegistryPostProcessorPriorityOrdered
的bean
注解方法,可以被加载进bean
定义。
TestBeanDefinitionRegistryPostProcessorPriorityOrdered
的postProcessBeanDefinitionRegistry
方法中注册了TestBeanDefinitionRegistryPostProcessor
的bean
定义。
TestBeanDefinitionRegistryPostProcessor
中的postProcessBeanDefinitionRegistry
又注册了UserDaoImple
的bean
定义。
注意
这个时候你会发现创建处理器的同时把配置类也创建了。
至此BeanDefinitionRegistryPostProcessor
的处理器全部处理完成,包括自定义的。后面就要处理BeanFactoryPostProcessor
的处理器啦,这个后面讲。
好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。
Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。
它的内容包括:
- 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
- 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
- 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
- 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
- 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
- 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
- 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
- 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw
目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:
想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询
同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。