> 文章列表 > dubbo3消费端bean字段名称引发的问题-dubbo2.7升级到dubbo3系列

dubbo3消费端bean字段名称引发的问题-dubbo2.7升级到dubbo3系列

dubbo3消费端bean字段名称引发的问题-dubbo2.7升级到dubbo3系列

最近在做老系统升级(springboot2+dubbo2.7.1+zookeeper+nacos-config),去掉zookeeper的注册中心,替换成nacos2.1版本(阿里云已经不支持1.X版本了)-对应的需要升级springboot和dubbo3。最终升级完成了,其中遇到的诸多问题,能记住多少就总结多少
有在升级过程中,遇到问题的小伙伴,欢迎交流。

报错

这个错误据官方说已经解决了,先看下错误

服务启动时报错:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'BaClient': Injection of @DubboReference dependencies is failed; nested exception is java.lang.IllegalArgumentException: Can not set com.dubbo3.test.api.AaUserServiceDubbo field com.dubbo3.test.consumer.service.BaClient.userService to com.sun.proxy.$Proxy87at 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: com.dubbo3.test.api.AaUserServiceDubbo field com.dubbo3.test.consumer.service.BaClient.userService to com.sun.proxy.$Proxy87at 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
修改BaClient AaUserServiceDubbo userService -> AaUserServiceDubbo aaUserServiceDubbo 后启动成功

因为我还有个服务UserServiceDubbo userServiceDubbo

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

我现在的dubbo版本是3.1.0 ,我看已经在注册时使用rename方式了。这也是要说的第二个问题。
userServiceDubbo#2

已存在bean名称,接口不同名

看看问题

Already exists another bean definition with the same bean name [userServiceDubbo], rename dubbo reference bean to [userServiceDubbo#2]. 
It is recommended to modify the name of one of the beans to avoid injection problems. prev: userServiceDubbo[ReferenceBean:com.dubbo3.test.api.UserServiceDubbo()],new: userServiceDubbo#2[ReferenceBean:com.dubbo3.test.api.AaUserServiceDubbo()].Please check private com.dubbo3.test.api.AaUserServiceDubbo com.dubbo3.test.consumer.service.CaClient.userServiceDubbo

这个时什么意思呢,简单说,就是,相同的bean 字段名单,但是接口不同名,发现类型不同,注册时,重新命名userServiceDubbo#2

修改下AaUserServiceDubbo aaUserServiceDubbo 就可以了。

可以看下源码:ReferenceAnnotationBeanPostProcessor

 public String registerReferenceBean(String propertyName, Class<?> injectedType, Map<String, Object> attributes, Member member) throws BeansException {boolean renameable = true;// referenceBeanNameString referenceBeanName = getAttribute(attributes, ReferenceAttributes.ID);if (hasText(referenceBeanName)) {renameable = false;} else {referenceBeanName = propertyName;}String checkLocation = "Please check " + member.toString();// convert annotation propsReferenceBeanSupport.convertReferenceProps(attributes, injectedType);// get interfaceString interfaceName = (String) attributes.get(ReferenceAttributes.INTERFACE);if (StringUtils.isBlank(interfaceName)) {throw new BeanCreationException("Need to specify the 'interfaceName' or 'interfaceClass' attribute of '@DubboReference' if enable generic. " + checkLocation);}// check reference keyString referenceKey = ReferenceBeanSupport.generateReferenceKey(attributes, applicationContext);// find reference bean name by reference keyList<String> registeredReferenceBeanNames = referenceBeanManager.getBeanNamesByKey(referenceKey);if (registeredReferenceBeanNames.size() > 0) {// found same name and reference keyif (registeredReferenceBeanNames.contains(referenceBeanName)) {return referenceBeanName;}}//check bean definitionif (beanDefinitionRegistry.containsBeanDefinition(referenceBeanName)) {BeanDefinition prevBeanDefinition = beanDefinitionRegistry.getBeanDefinition(referenceBeanName);String prevBeanType = prevBeanDefinition.getBeanClassName();String prevBeanDesc = referenceBeanName + "[" + prevBeanType + "]";String newBeanDesc = referenceBeanName + "[" + referenceKey + "]";if (isReferenceBean(prevBeanDefinition)) {//check reference keyString prevReferenceKey = ReferenceBeanSupport.generateReferenceKey(prevBeanDefinition, applicationContext);if (StringUtils.isEquals(prevReferenceKey, referenceKey)) {//found matched dubbo reference bean, ignore registerreturn referenceBeanName;}//get interfaceName from attributeAssert.notNull(prevBeanDefinition, "The interface class of ReferenceBean is not initialized");prevBeanDesc = referenceBeanName + "[" + prevReferenceKey + "]";}// bean name from attribute 'id' or java-config bean, cannot be renamedif (!renameable) {throw new BeanCreationException("Already exists another bean definition with the same bean name [" + referenceBeanName + "], " +"but cannot rename the reference bean name (specify the id attribute or java-config bean), " +"please modify the name of one of the beans: " +"prev: " + prevBeanDesc + ", new: " + newBeanDesc + ". " + checkLocation);}// the prev bean type is different, rename the new reference beanint index = 2;String newReferenceBeanName = null;while (newReferenceBeanName == null || beanDefinitionRegistry.containsBeanDefinition(newReferenceBeanName)|| beanDefinitionRegistry.isAlias(newReferenceBeanName)) {newReferenceBeanName = referenceBeanName + "#" + index;index++;// double check found same name and reference keyif (registeredReferenceBeanNames.contains(newReferenceBeanName)) {return newReferenceBeanName;}}newBeanDesc = newReferenceBeanName + "[" + referenceKey + "]";logger.warn("Already exists another bean definition with the same bean name [" + referenceBeanName + "], " +"rename dubbo reference bean to [" + newReferenceBeanName + "]. " +"It is recommended to modify the name of one of the beans to avoid injection problems. " +"prev: " + prevBeanDesc + ", new: " + newBeanDesc + ". " + checkLocation);referenceBeanName = newReferenceBeanName;}attributes.put(ReferenceAttributes.ID, referenceBeanName);// If registered matched reference before, just register aliasif (registeredReferenceBeanNames.size() > 0) {beanDefinitionRegistry.registerAlias(registeredReferenceBeanNames.get(0), referenceBeanName);referenceBeanManager.registerReferenceKeyAndBeanName(referenceKey, referenceBeanName);return referenceBeanName;}Class interfaceClass = injectedType;// TODO Only register one reference bean for same (group, interface, version)// Register the reference bean definition to the beanFactoryRootBeanDefinition beanDefinition = new RootBeanDefinition();beanDefinition.setBeanClassName(ReferenceBean.class.getName());beanDefinition.getPropertyValues().add(ReferenceAttributes.ID, referenceBeanName);// set attribute instead of property valuesbeanDefinition.setAttribute(Constants.REFERENCE_PROPS, attributes);beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_CLASS, interfaceClass);beanDefinition.setAttribute(ReferenceAttributes.INTERFACE_NAME, interfaceName);// create decorated definition for reference bean, Avoid being instantiated when getting the beanType of ReferenceBean// see org.springframework.beans.factory.support.AbstractBeanFactory#getTypeForFactoryBean()GenericBeanDefinition targetDefinition = new GenericBeanDefinition();targetDefinition.setBeanClass(interfaceClass);beanDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, referenceBeanName + "_decorated"));// signal object type since Spring 5.2beanDefinition.setAttribute(Constants.OBJECT_TYPE_ATTRIBUTE, interfaceClass);beanDefinitionRegistry.registerBeanDefinition(referenceBeanName, beanDefinition);referenceBeanManager.registerReferenceKeyAndBeanName(referenceKey, referenceBeanName);logger.info("Register dubbo reference bean: " + referenceBeanName + " = " + referenceKey + " at " + member);return referenceBeanName;}