dubbo icon indicating copy to clipboard operation
dubbo copied to clipboard

3.0.6 引用dubbo服务时候报错

Open xiangzz159 opened this issue 3 years ago • 9 comments

  • [ ] I have searched the issues of this repository and believe that this is not a duplicate.

Environment

  • Dubbo version: 3.0.6
  • Operating System version: MacOS 10.15.7
  • Java version: 1.8.0_231

Steps to reproduce this issue

image

image

image

image

  1. 服务启动时报错:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'DClient': Injection of @DubboReference dependencies is failed; nested exception is java.lang.IllegalArgumentException: Can not set com.xsyx.router.api.feature.UserAInfo field com.xsyx.router.client.client.DClient.userInfo to com.sun.proxy.$Proxy87
	at org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor.postProcessPropertyValues(ReferenceAnnotationBeanPostProcessor.java:326)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1418)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758)
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:438)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:337)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1336)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1325)
	at com.xsyx.router.client.ClientApplication.main(ClientApplication.java:16)
Caused by: java.lang.IllegalArgumentException: Can not set com.xsyx.router.api.feature.UserAInfo field com.xsyx.router.client.client.DClient.userInfo to com.sun.proxy.$Proxy87
	at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
	at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
	at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)
	at java.lang.reflect.Field.set(Field.java:764)
	at org.apache.dubbo.config.spring.beans.factory.annotation.AbstractAnnotationBeanPostProcessor$AnnotatedInjectElement.inject(AbstractAnnotationBeanPostProcessor.java:470)
	at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119)
	at org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor.postProcessPropertyValues(ReferenceAnnotationBeanPostProcessor.java:322)
	... 17 common frames omitted
  1. 修改DClient UserAInfo userInfo -> UserAInfo userAInfo 后启动成功

Pls. provide [GitHub address] to reproduce this issue.

Expected Behavior

Actual Behavior

If there is an exception, please attach the exception trace:

Just put your stack trace here!

xiangzz159 avatar Jul 18 '22 09:07 xiangzz159

我理解原因是spring在生成bean DClient的过程中,当赋值属性UserAInfo userInfo时,是根据名称userInfo查找对应的bean,而不是根据类型UserAInfo查找bean,这个是spring的流程,应该不算dubbo的bug

chenziqiang666 avatar Jul 19 '22 08:07 chenziqiang666

image 这边的代码有问题,beanDefinitionRegistry没有找到已经注册的bean,所以index没有刷新,修改index为一个比较大的值后能正常启动

xiangzz159 avatar Jul 20 '22 02:07 xiangzz159

我觉得这种注入的写法是不规范的,当然dubbo 是需要解决这种情况的。 @xiangzz159 @chenziqiang666 #10359

liufeiyu1002 avatar Jul 23 '22 17:07 liufeiyu1002

BCD三个类在注入依赖bean的时候,因为这三的属性名称一样且类型不一样(会走入你前面截图的逻辑里),按理注入的beanName应该分别为userInfo、userInfo#2、userInfo#3。我理解应该不会出现你所描述的 beanDefinitionRegistry没有找到已经注册的bean,我本地试了下没有问题,方便的话可以发一下你的demo我本地复现一下。

BurningCN avatar Jul 24 '22 07:07 BurningCN

BCD三个类在注入依赖bean的时候,因为这三的属性名称一样且类型不一样(会走入你前面截图的逻辑里),按理注入的beanName应该分别为userInfo、userInfo#2、userInfo#3。我理解应该不会出现你所描述的 beanDefinitionRegistry没有找到已经注册的bean,我本地试了下没有问题,方便的话可以发一下你的demo我本地复现一下。

他截图部分的代码 会在 postProcessBeanFactory 和 postProcessMergedBeanDefinition 俩次触发执行, 第一次触发:(postProcessBeanFactory ) A类 beanDefinitionRegistry.registerBeanDefinition("test", UserInfo的beanDefinition);
B类 beanDefinitionRegistry.registerBeanDefinition("userInfo", MessageInfo的beanDefinition); C类 注册了别名 beanDefinitionRegistry.registerAlias("test", "userInfo#2"); D 类 beanDefinitionRegistry.registerBeanDefinition("userInfo#2", UserAInfo的beanDefinition); 第二次触发:(postProcessMergedBeanDefinition ) image A类 B类 在上图代码中会从缓存中获取到直接返回 C类传入的referenceBeanName是userInfo 在 UserInfo类型对应的缓存中是 test/userInfo#2 没有命中缓存,会走到 image 这部分执行时 C类获取到 newReferenceBeanName 应该是 userInfo#3 ,因为 userInfo 和 userInfo#2 被 B 和 D 注册到了beanDefinitionRegistry中 ,此时会继续注册alias beanDefinitionRegistry.registerAlias("test", "userInfo#3"); D 类 传入的referenceBeanName是userInfo 在 UserAInfo类型对应的缓存中是 userInfo#2 没有命中缓存,走到上图红框中执行 D 类获取到 newReferenceBeanName 应该是 userInfo#3 ,因为userInfo被B注册 userInfo#2 被他之前自己注册过了,之后会注册别名 userInfo#3: userInfo#2 此时因为别名 userInfo#3 被 test 注册过了 如果 allowBeanDefinitionOverriding 为false 则会抛出异常 image image 如果允许覆盖则 别名会变成如图所示 image 之后当前D类的 AnnotatedFieldElement的 injectedObject 值被设置为 userInfo#3 在D类执行属性注入时 InjectedElement.inject 从spring中获取bean对象是 beanName 是 AnnotatedFieldElement.injectedObject 的值 image 此时从spring 获取bean的时候 image 会从 别名中获取到 真的 注入容器中的那个名称 test test 是UserInfo 类型的, 而D类注入的 类型UserAInfo image 如图 field 是 UserAInfo injectObject 是 UserInfo类型的 dubbo 代理类,此时类型不匹配 会抛出异常

liufeiyu1002 avatar Jul 24 '22 13:07 liufeiyu1002

BCD三个类在注入依赖bean的时候,因为这三的属性名称一样且类型不一样(会走入你前面截图的逻辑里),按理注入的beanName应该分别为userInfo、userInfo#2、userInfo#3。我理解应该不会出现你所描述的 beanDefinitionRegistry没有找到已经注册的bean,我本地试了下没有问题,方便的话可以发一下你的demo我本地复现一下。

所以在此处 image 对newReferenceBeanName的要求应该是 没有被注册到 beanDefinitionRegistry中 且 别名中也没注册过当前名称,在生成新的newReferenceBeanName名称时 应该二次检查之前是否已经使用当前名称注册过,避免重复的注入多个别名

liufeiyu1002 avatar Jul 24 '22 13:07 liufeiyu1002

@liufeiyu1002 感谢,分析很详细透彻。也是因为 postProcessBeanFactorypostProcessMergedBeanDefinitionregisterReferenceBean方法的重复调用,没有处理好同一个bean在beanName冲突对别名处理的可重入问题。一个bean(C类)因为beanName冲突而注册了别名(userInfo#2),但是在重复调用的时候(依然是这个bean),没有处理先前该bean(C类)已经注册过的别名(userInfo#2),导致起新的别名(userInfo#3)并注册,而其他bean(D类)若也用了这个别名(userInfo#3),导致相同的别名(userInfo#3)注册到不同的原beanName(test和userInfo#2)上,就出现了问题。

c类 beanDefinitionRegistry.registerAlias("test", "userInfo#2") beanDefinitionRegistry.registerAlias("test", "userInfo#3")

d类 beanDefinitionRegistry.registerAlias("userInfo#2", "userInfo#3") // 在该处执行时,因为userInfo#3这个别名先前给test了,这里又想给userInfo#2,就发生了一些问题

BurningCN avatar Jul 24 '22 14:07 BurningCN

PR #10359, by liufeiyu1002

BurningCN avatar Jul 24 '22 15:07 BurningCN

BCD三个类在注入依赖bean的时候,因为这三的属性名称一样且类型不一样(会走入你前面截图的逻辑里),按理注入的beanName应该分别为userInfo、userInfo#2、userInfo#3。我理解应该不会出现你所描述的 beanDefinitionRegistry没有找到已经注册的bean,我本地试了下没有问题,方便的话可以发一下你的demo我本地复现一下。

https://github.com/xiangzz159/dubbo-client-demo

xiangzz159 avatar Jul 26 '22 02:07 xiangzz159

Fixed in https://github.com/apache/dubbo/pull/10359, please upgrade to the 3.0.11 bugfix version.

chickenlj avatar Sep 02 '22 02:09 chickenlj

这个问题好像还存在,把有问题的变量名改一下就好了; 有问题写法: @DubboReference private ProjectService projectService; 没问题写法: @DubboReference private ProjectService gaeaProjectService;

cycle2zhou avatar Feb 15 '23 06:02 cycle2zhou