記錄一次因創(chuàng)建BeanDefinitonRegistryPostProcessor的Bean導(dǎo)致@Configuration注解類中屬性失效的問題

起因

事情的起因是這樣的,在開發(fā)基于nacos的動(dòng)態(tài)線程池項(xiàng)目時(shí),一開始選用的nacos-pring-context的版本為:0.2.2-RC1,版本中@NacosConfigListener注解的dataId與groupId不支持動(dòng)態(tài)解析,于是相對(duì)其進(jìn)行改造。
查看其源碼發(fā)現(xiàn)起作用的是NacosConfigListenerMethodProcessor類。于是產(chǎn)生了一個(gè)想法重新創(chuàng)建創(chuàng)建一個(gè)CustomNacosConfigListenerMethodProcessor類注冊(cè)到容器中,將NacosConfigListenerMethodProcessor的BeanDefinition進(jìn)行清除,于是創(chuàng)建了一個(gè)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();
    }
}

現(xiàn)象

到此以為萬(wàn)事大吉,然后去進(jìn)行測(cè)試,突然發(fā)現(xiàn)項(xiàng)目報(bào)錯(cuò),原因是@Value注解的applicationName字段為null,我把ChangeDefinitionRegistryPostProcessor聲明bean的部分注釋掉,項(xiàng)目就可以正常啟動(dòng)

探查原因

為什么在@ Configuration注解的類中聲明這個(gè)ChangeDefinitionRegistryPostProcessor的bean會(huì)導(dǎo)致屬性注入失敗呢,這里需要提前了解三個(gè)知識(shí)點(diǎn)

  1. @value注解的注入原理是什么,在哪個(gè)類里面進(jìn)行的,執(zhí)行時(shí)機(jī)是什么,這個(gè)BeanPostPerocessor什么時(shí)候加入到BeanPostProcessor處理集合中的
  2. @Bean注解創(chuàng)建bean的過程是什么,這其中會(huì)對(duì)DynamicExecutorConfiguration產(chǎn)生什么影響
  3. ChangeDefinitionRegistryPostProcessor的執(zhí)行時(shí)機(jī)是什么時(shí)候
    下面來解決這三個(gè)問題
    第一個(gè)問題:@value注解的注入原理是什么,在哪個(gè)類里面進(jìn)行的,執(zhí)行時(shí)機(jī)是什么?
    @value注解的代碼處理是在AutowiredAnnotationBeanPostProcessor的postProcessProperties方法進(jìn)行處理的,而方法的執(zhí)行時(shí)機(jī)是在bean的生命周期中屬性注入節(jié)點(diǎn)執(zhí)行的
    image.png

    image.png

    那什么時(shí)候加入到處理器集合中的呢?
    是在refresh方法的registerBeanPostProcessor(beanFactory)方法中加入處理器集合的
    image.png

    第二個(gè)問題:@Bean注解創(chuàng)建bean的過程是什么,這其中會(huì)對(duì)DynamicExecutorConfiguration產(chǎn)生什么影響?
    我們需要知道@Bean的bean的初始化的過程是利用的反射原理來實(shí)現(xiàn),也就是說在實(shí)例化ChangeDefinitionRegistryPostProcessor這個(gè)Bean之前我們需要先創(chuàng)建DynamicExecutorConfiguration這個(gè)類的對(duì)象,也就是先創(chuàng)建DynamicExecutorConfiguration這個(gè)bean
    因此這里有一個(gè)點(diǎn)需要明白在創(chuàng)建ChangeDefinitionRegistryPostProcessor這個(gè)bean之前一定是需要先創(chuàng)建好DynamicExecutorConfiguration這個(gè)bean的
    第三個(gè)問題:ChangeDefinitionRegistryPostProcessor的執(zhí)行時(shí)機(jī)是什么時(shí)候?
    我們來看ChangeDefinitionRegistryPostProcessor屬于BeanDefinitionRegistryPostProcessor,因此他的執(zhí)行時(shí)機(jī)是在invokeBeanFactoryPostProcessor(beanFactory)方法中
    image.png

    需要特別提醒與在第一個(gè)問題中AutowiredAnnotationBeanPostProcessor是何時(shí)計(jì)入的BeanPostProcessor處理集合中的,對(duì),是在后面的registerBeanPostProcessor(beanFactory)中,這些意味著在執(zhí)行invokeBeanFacotryPostProcessors(beanFacotruy)時(shí),容器中是沒有AutowiredAnnotationBeanPostProcessor這個(gè)處理Bean的

到此你是不是發(fā)現(xiàn)了什么?是的,你猜的很多,當(dāng)DynamicExecutorConfiguration中聲明了ChangeDefinitionRegistryPostProcessor這個(gè)bean時(shí),在執(zhí)行到invokeBeanFacotryPostProcessors(beanFactory)這個(gè)方法時(shí)會(huì)加載ChangeDefinitionRegistryPostProcessor這個(gè)bean,而加載ChangeDefinitionRegistryPostProcessor的bean時(shí),需要先加載DynamicExecutorConfiguration這個(gè)bean,因此在初始化單例bean
DynamicExecutorConfiguration的過程的在屬性注入populateBean()階段由于還沒有AutowiredAnnotationBeanPostProcessor這個(gè)bean,導(dǎo)致無法完成@Value的屬性注入,又因?yàn)樯傻氖菃卫齜ean,后續(xù)再使用DynamicExecutorConfiguration這個(gè)bean時(shí)都是從一級(jí)緩存中獲取的,而這個(gè)bean是未完成屬性注入的bean
因此這也解釋了為什么DynamicExecutorConfiguration一旦聲明ChangeDefinitionRegistryPostProcessor這個(gè)bean時(shí),就會(huì)導(dǎo)致屬性注入失敗的問題

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容