子模块Spring上下文刷新报错:No bean named 'referenceAnnotationBeanPostProcessor'
- [x ] I have searched the issues of this repository and believe that this is not a duplicate.
Environment
- Dubbo version: 3.0.9
- Operating System version: Mac OS
- Java version: jdk11
Steps to reproduce this issue
参考 https://github.com/sofastack/sofa-boot/issues/998 在和Sofa boot整合多模块隔离Spring上下文时, 发现ReferenceAnnotationBeanPostProcessor postProcessBeanFactory 会销毁自己。
if (beanFactory instanceof AbstractBeanFactory) {
List<BeanPostProcessor> beanPostProcessors = ((AbstractBeanFactory) beanFactory).getBeanPostProcessors();
for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
if (beanPostProcessor == this) {
// This bean has been registered as BeanPostProcessor at org.apache.dubbo.config.spring.context.DubboInfraBeanRegisterPostProcessor.postProcessBeanFactory()
// so destroy this bean here, prevent register it as BeanPostProcessor again, avoid cause BeanPostProcessorChecker detection error
beanDefinitionRegistry.removeBeanDefinition(BEAN_NAME);
break;
}
}
}
导致子模块的Spring 上下刷新时遇到DubboInfraBeanRegisterPostProcessor 执行 postProcessBeanFactory时ReferenceAnnotationBeanPostProcessor不存在报错,项目无法启动.
// In Spring 3.2.x, registry may be null because do not calling postProcessBeanDefinitionRegistry method before postProcessBeanFactory
if (registry != null) {
// register ReferenceAnnotationBeanPostProcessor early before PropertySourcesPlaceholderConfigurer/PropertyPlaceholderConfigurer
// for processing early init ReferenceBean
ReferenceAnnotationBeanPostProcessor referenceAnnotationBeanPostProcessor = beanFactory.getBean(
ReferenceAnnotationBeanPostProcessor.BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class);
beanFactory.addBeanPostProcessor(referenceAnnotationBeanPostProcessor);
// register PropertySourcesPlaceholderConfigurer bean if not exits
DubboBeanUtils.registerPlaceholderConfigurerBeanIfNotExists(beanFactory, registry);
}
If there is an exception, please attach the exception trace:
022-07-05 14:04:45.362 ERROR 2277 --- [y.uims2.service] com.alipay.sofa : SOFA-BOOT-01-11002: Refreshing Spring Application Context of module com.my.uims2.service got an error org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'referenceAnnotationBeanPostProcessor' available at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:872) at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1344) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:309) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:283) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:213) at org.apache.dubbo.config.spring.context.DubboInfraBeanRegisterPostProcessor.postProcessBeanFactory(DubboInfraBeanRegisterPostProcessor.java:68) at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:325) at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:147) at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:746) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:564) at com.alipay.sofa.isle.stage.SpringContextInstallStage.doRefreshSpringContext(SpringContextInstallStage.java:313) at com.alipay.sofa.isle.stage.SpringContextInstallStage$1.run(SpringContextInstallStage.java:278) at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at com.alipay.sofa.common.thread.ExecutingRunnable.run(ExecutingRunnable.java:84) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:829)
能提供一个简单的 demo 不,我这边尝试复现下
OK,稍等,我去上传下代码
能提供一个简单的 demo 不,我这边尝试复现下
@AlbumenJ https://github.com/wj-ddd-practice/multi-spring-context-demo
看了下 sofa 切换了 beanFactory,然后这个 beanFactory 没有触发 org.apache.dubbo.config.spring.context.DubboSpringInitializer#initialize,导致有些数据没注入。这个得看下是不是 sofa 那边创建 beanFactory 的时候缺少了触发的环节。
dubbo是在启动模块demo-application加入的dubbo依赖, Root Spring context触发了org.apache.dubbo.config.spring.context.DubboSpringInitializer#initialize,这块是没问题的。 接下来demo-service是个sofa module,sofa会给这个模块初始化一个独立的Spring 上下文, demo-service这个模块因为没有dubbo依赖,所以不会触发org.apache.dubbo.config.spring.context.DubboSpringInitializer#initialize。 但是demo-service的子beanFactory会从父beanFactory获取postBeanProcessBeans, 所以demo-service的子beanFactory refresh的时候会触发DubboInfraBeanRegisterPostProcessor#postProcessBeanFactory, 然而ReferenceAnnotationBeanPostProcessor在Root Spring上下文已经被自己销毁,所以模块的子Spring上下文和RootSpring上下文都找不到这个bean,最终报No bean named 'referenceAnnotationBeanPostProcessor' available。 demo-service模块本身就没有dubbo依赖,也不需要去触发org.apache.dubbo.config.spring.context.DubboSpringInitializer#initialize。
目前在本地,我把ReferenceAnnotationBeanPostProcessor如下这段代码注释掉以后就没有没问题的。 但不确定是否会有其他影响? 、、、 if (beanFactory instanceof AbstractBeanFactory) { List<BeanPostProcessor> beanPostProcessors = ((AbstractBeanFactory) beanFactory).getBeanPostProcessors(); for (BeanPostProcessor beanPostProcessor : beanPostProcessors) { if (beanPostProcessor == this) { // This bean has been registered as BeanPostProcessor at org.apache.dubbo.config.spring.context.DubboInfraBeanRegisterPostProcessor.postProcessBeanFactory() // so destroy this bean here, prevent register it as BeanPostProcessor again, avoid cause BeanPostProcessorChecker detection error beanDefinitionRegistry.removeBeanDefinition(BEAN_NAME); break; } } } 、、、
这段注释也没看特别明白,DubboInfraBeanRegisterPostProcessor也没去注册ReferenceAnnotationBeanPostProcessor bean,只是为了保证ReferenceAnnotationBeanPostProcessor比PropertySourcesPlaceholderConfigurer先执行。 、、、 // In Spring 3.2.x, registry may be null because do not calling postProcessBeanDefinitionRegistry method before postProcessBeanFactory if (registry != null) { // register ReferenceAnnotationBeanPostProcessor early before PropertySourcesPlaceholderConfigurer/PropertyPlaceholderConfigurer // for processing early init ReferenceBean ReferenceAnnotationBeanPostProcessor referenceAnnotationBeanPostProcessor = beanFactory.getBean( ReferenceAnnotationBeanPostProcessor.BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class); beanFactory.addBeanPostProcessor(referenceAnnotationBeanPostProcessor);
// register PropertySourcesPlaceholderConfigurer bean if not exits
DubboBeanUtils.registerPlaceholderConfigurerBeanIfNotExists(beanFactory, registry);
}
、、、
@AlbumenJ 大佬怎么看?
- 把ReferenceAnnotationBeanPostProcessor 销毁自己这端代码去掉,但可能会产生哪些问题?
- ReferenceAnnotationBeanPostProcessor 加个非空判断,如果ReferenceAnnotationBeanPostProcessor bean存在再触发addBeanPostProcessor逻辑
#10451 @AlbumenJ @wujun27
check if #10451 fixed