起因
事情的起因是這樣的,在開發(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)
- @value注解的注入原理是什么,在哪個(gè)類里面進(jìn)行的,執(zhí)行時(shí)機(jī)是什么,這個(gè)BeanPostPerocessor什么時(shí)候加入到BeanPostProcessor處理集合中的
- @Bean注解創(chuàng)建bean的過程是什么,這其中會(huì)對(duì)DynamicExecutorConfiguration產(chǎn)生什么影響
- 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)致屬性注入失敗的問題



