2023-09-16  阅读(2)
原文作者:王伟王胖胖 原文地址: https://blog.csdn.net/wangwei19871103/article/details/105005336

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后置处理器处理流程

202309162311422721.png

处理一般排序的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 实现了BeanDefinitionRegistryPostProcessorOrdered

    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方法:

202309162311433542.png

202309162311439923.png

注意

这里要注意,这个时候因为要创建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");
        }
    }

结果:

202309162311444684.png

202309162311448865.png
而且在里面又注册了一个UserDaoImple

202309162311458746.png
至此,所有实现的BeanDefinitionRegistryPostProcessor接口的处理器都处理完成了。
我们的自定义扩展顺序可以看这里:

202309162311464287.png

扩展点顺序

ConfigurationClassPostProcessor处理MyConfigMyConfig定义了TestBeanDefinitionRegistryPostProcessorPriorityOrderedbean注解方法,可以被加载进bean定义。

202309162311472558.png
TestBeanDefinitionRegistryPostProcessorPriorityOrderedpostProcessBeanDefinitionRegistry方法中注册了TestBeanDefinitionRegistryPostProcessorbean定义。

202309162311477479.png
TestBeanDefinitionRegistryPostProcessor中的postProcessBeanDefinitionRegistry又注册了UserDaoImplebean定义。

2023091623114831110.png

注意

这个时候你会发现创建处理器的同时把配置类也创建了。

2023091623114881211.png

至此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] ,回复【面试题】 即可免费领取。

阅读全文