记录一次因创建BeanDefinitonRegistryPost

2024-05-25  本文已影响0人  酱油瓶儿_fea9

起因

事情的起因是这样的,在开发基于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时,就会导致属性注入失败的问题

上一篇下一篇

猜你喜欢

热点阅读