美文网首页
记录一次因创建BeanDefinitonRegistryPost

记录一次因创建BeanDefinitonRegistryPost

作者: 酱油瓶儿_fea9 | 来源:发表于2024-05-25 18:16 被阅读0次

    起因

    事情的起因是这样的,在开发基于nacos的动态线程池项目时,一开始选用的nacos-pring-context的版本为:0.2.2-RC1,版本中@NacosConfigListener注解的dataId与groupId不支持动态解析,于是相对其进行改造。
    查看其源码发现起作用的是NacosConfigListenerMethodProcessor类。于是产生了一个想法重新创建创建一个CustomNacosConfigListenerMethodProcessor类注册到容器中,将NacosConfigListenerMethodProcessor的BeanDefinition进行清除,于是创建了一个ChangeDefinitionRegistryPostProcessor

    public class ChangeDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
        @Override
        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
            if(registry.containsBeanDefinition(NacosConfigListenerMethodProcessor.BEAN_NAME)){
                registry.removeBeanDefinition(NacosConfigListenerMethodProcessor.BEAN_NAME);
                BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(CustomNacosConfigListenerMethodProcessor.class);
                // ROLE_INFRASTRUCTURE
                beanDefinitionBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
                // Register
                registry.registerBeanDefinition(NacosConfigListenerMethodProcessor.BEAN_NAME, beanDefinitionBuilder.getBeanDefinition());
            }
        }
    
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    
        }
    }
    

    然后在DynamicExecutorConfiguration中声明该bean

    @Configuration
    @EnableNacos(globalProperties = @NacosProperties())
    public class DynamicExecutorConfiguration implements ApplicationEventPublisherAware {
        public static final String DYNAMIC_EXECUTOR_PREFIX = "dynamic.executors";
    
        ApplicationEventPublisher publisher;
    
        @Value("${spring.application.name}")
        private String applicationName;
    
        @Bean
        ChangeDefinitionRegistryPostProcessor changeDefinitionRegistryPostProcessor(){
            return new ChangeDefinitionRegistryPostProcessor();
        }
    }
    

    现象

    到此以为万事大吉,然后去进行测试,突然发现项目报错,原因是@Value注解的applicationName字段为null,我把ChangeDefinitionRegistryPostProcessor声明bean的部分注释掉,项目就可以正常启动

    探查原因

    为什么在@ Configuration注解的类中声明这个ChangeDefinitionRegistryPostProcessor的bean会导致属性注入失败呢,这里需要提前了解三个知识点

    1. @value注解的注入原理是什么,在哪个类里面进行的,执行时机是什么,这个BeanPostPerocessor什么时候加入到BeanPostProcessor处理集合中的
    2. @Bean注解创建bean的过程是什么,这其中会对DynamicExecutorConfiguration产生什么影响
    3. ChangeDefinitionRegistryPostProcessor的执行时机是什么时候
      下面来解决这三个问题
      第一个问题:@value注解的注入原理是什么,在哪个类里面进行的,执行时机是什么?
      @value注解的代码处理是在AutowiredAnnotationBeanPostProcessor的postProcessProperties方法进行处理的,而方法的执行时机是在bean的生命周期中属性注入节点执行的 image.png
      image.png
      那什么时候加入到处理器集合中的呢?
      是在refresh方法的registerBeanPostProcessor(beanFactory)方法中加入处理器集合的
      image.png
      第二个问题:@Bean注解创建bean的过程是什么,这其中会对DynamicExecutorConfiguration产生什么影响?
      我们需要知道@Bean的bean的初始化的过程是利用的反射原理来实现,也就是说在实例化ChangeDefinitionRegistryPostProcessor这个Bean之前我们需要先创建DynamicExecutorConfiguration这个类的对象,也就是先创建DynamicExecutorConfiguration这个bean
      因此这里有一个点需要明白在创建ChangeDefinitionRegistryPostProcessor这个bean之前一定是需要先创建好DynamicExecutorConfiguration这个bean的
      第三个问题:ChangeDefinitionRegistryPostProcessor的执行时机是什么时候?
      我们来看ChangeDefinitionRegistryPostProcessor属于BeanDefinitionRegistryPostProcessor,因此他的执行时机是在invokeBeanFactoryPostProcessor(beanFactory)方法中 image.png
      需要特别提醒与在第一个问题中AutowiredAnnotationBeanPostProcessor是何时计入的BeanPostProcessor处理集合中的,对,是在后面的registerBeanPostProcessor(beanFactory)中,这些意味着在执行invokeBeanFacotryPostProcessors(beanFacotruy)时,容器中是没有AutowiredAnnotationBeanPostProcessor这个处理Bean的

    到此你是不是发现了什么?是的,你猜的很多,当DynamicExecutorConfiguration中声明了ChangeDefinitionRegistryPostProcessor这个bean时,在执行到invokeBeanFacotryPostProcessors(beanFactory)这个方法时会加载ChangeDefinitionRegistryPostProcessor这个bean,而加载ChangeDefinitionRegistryPostProcessor的bean时,需要先加载DynamicExecutorConfiguration这个bean,因此在初始化单例bean
    DynamicExecutorConfiguration的过程的在属性注入populateBean()阶段由于还没有AutowiredAnnotationBeanPostProcessor这个bean,导致无法完成@Value的属性注入,又因为生成的是单例bean,后续再使用DynamicExecutorConfiguration这个bean时都是从一级缓存中获取的,而这个bean是未完成属性注入的bean
    因此这也解释了为什么DynamicExecutorConfiguration一旦声明ChangeDefinitionRegistryPostProcessor这个bean时,就会导致属性注入失败的问题

    相关文章

      网友评论

          本文标题:记录一次因创建BeanDefinitonRegistryPost

          本文链接:https://www.haomeiwen.com/subject/vmbfqjtx.html