Dubbo配置注册中心设置application的name使用驼峰命名法可能存在的隐藏启动异常问题

原创/朱季谦

首先,先提一个建议,在SpringBoot+Dubbo项目中,Dubbo配置注册中心设置的application命名name的值,最好使用xxx-xxx-xxx这样格式的,避免随便使用驼峰命名。因为使用驼峰命名法,在Spring的IOC容器当中,很可能会出现一些导致项目启动失败的坑,例如,会出现这样的异常报错:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userController': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'userService' is expected to be of type 'com.xxx.xxx.xxx.service.UserService' but was actually of type 'org.apache.dubbo.config.ApplicationConfig'

在说明该问题之前,首先,需要提一下org.apache.dubbo.config.ApplicationConfig这个类,这是一个Dubbo的应用配置类,它用在哪里呢?

在SpringBoot 2.x+Dubbo项目当中,主流都是使用yaml文件设置项目环境依赖参数,不同的组件,其配置类的实例化各有差异。

Dubbo初始化配置类主要有以下——

序号类名用途说明
1ApplicationConfig当前应用配置提供者或者消费者配置当前应用信息,一般以属性name区分各应用
2MonitorConfig监控中心配置配置连接监控中心monitor参数
3RegistryConfig连接注册中心配置配置Dubbo用到的注册中心
4ProtocolConfig服务提供者协议配置配置提供方的远程通信协议
........................

这些配置类的实现原理基本大同小异,本文主要以ApplicationConfig配置类做讲解分析。

在yaml配置文件里,Dubbo的配置例子如下——

dubbo:
  application:
    name: userService
  registry:
    address: zookeeper://127.0.0.1:2181
    timeout: 10000
  protocol:
    name: dubbo
    port: 20880

这个配置可以拆开如下图这样看,便能一眼看懂它们分别属于哪个配置类——

image

当在yaml文件这样配置后,当项目启动时,会自动获取这些参数,然后初始化到对应的配置类当中,例如,application中的name值就会设置到ApplicationConfig类对象里——

image

在SpringBoot中,这个ApplicationConfig对象会在普通bean初始化之前,就已经装载到IOC容器当中,以name的值做该bean名,同时,会以name:className的方式存储在Spring的bean别名缓存aliasMap当中,这就出现一个问题,假如该项目当中存在同名bean注解的话,会出现什么样情况呢?

例如,当SpringBoot的Dubbo配置如前边一样,以字符串“userService”做ApplicationConfig的name值,同时,controller层有以下代码——

@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    private UserService userService;
  
    ......
}

我们可以在IOC容器过程的AbstractBeanFactory类中的doGetBean(String name, @Nullable Class requiredType, @Nullable Object[] args, boolean typeCheckOnly)方法截图处打一个针对userService的断点——

image

截图里的逻辑,其实是在对注解有@RestController的UserController类做IOC过程中,会对其通过 @Resource设置的属性userService做依赖注入过程,首先,会去bean别名aliasMap缓存当中看是否能查询到,我们进入到transformedBeanName(name)方法底层——

public String canonicalName(String name) {
   String canonicalName = name;
   // Handle aliasing...
   String resolvedName;
   do {
      resolvedName = this.aliasMap.get(canonicalName);
      if (resolvedName != null) {
         canonicalName = resolvedName;
      }
   }
   while (resolvedName != null);
   return canonicalName;
}

此时,this.aliasMap缓存里已经有值了,主要都是Dubbo相关的,这说明Dubbo会在普通自定义Bean前就做了IOC注入,我们可以看到,前边提到的ApplicationConfig对象class类名,已经缓存在aliasMap当中,其key值,正好yaml配置文件里设置的name值。当以“userService”字符串取aliasMap获取,是可以拿到值的——

image

但是,这里注意一点,此刻debug这一步doGetBean,理应依赖注入的是UserService类而不是ApplicationConfig类——

image

然而实际情况是,此时,通过方法Object sharedInstance = getSingleton(beanName)从IOC三级缓存之一的单例池里获取到的则是ApplicationConfig已经初始化成单例bean的对象——

image

这将会出现什么情况呢?

在 doGetBean方法最后,会做一步这样操作,将需要初始化的bean类型requiredType与通过“userService”从单例池里获取到的实际bean类型做比较——

// Check if required type matches the type of the actual bean instance.
//检查所需类型是否与实际bean实例的类型匹配
if (requiredType != null && !requiredType.isInstance(bean)) {
   try {
      T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
      if (convertedBean == null) {
         throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
      }
      return convertedBean;
   }
   catch (TypeMismatchException ex) {
      if (logger.isTraceEnabled()) {
         logger.trace("Failed to convert bean '" + name + "' to required type '" +
               ClassUtils.getQualifiedName(requiredType) + "'", ex);
      }
      throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
   }
}

结果可想而知,一个是UserService类,一个是ApplicationConfig类,两者肯定不匹配,那么就会执行抛出异常throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());

public BeanNotOfRequiredTypeException(String beanName, Class<?> requiredType, Class<?> actualType) {
   super("Bean named '" + beanName + "' is expected to be of type '" + ClassUtils.getQualifiedName(requiredType) +
         "' but was actually of type '" + ClassUtils.getQualifiedName(actualType) + "'");
   this.beanName = beanName;
   this.requiredType = requiredType;
   this.actualType = actualType;
}

debug到这一步,其错误提示,刚好就是——

Bean named 'userService' is expected to be of type 'com.xxx.xxx.xxx.service.UserService' but was actually of type 'org.apache.dubbo.config.ApplicationConfig

因此,就说明一个问题,当Dubbo应用配置application的name使用驼峰命名,例如,本文中的userService,刚好又有某个地方用到类似这样注解的属性依赖注入 private UserService userService,那么,项目在启动过程中,就会出现类似本文中提到的项目启动异常。

可见,在application的name值使用xxx-xxx-xx这样方式命名会更好些。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/186831.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据结构总复习

文章目录 线性表动态分配的顺序存储结构链式存储 线性表 动态分配的顺序存储结构 通过分析代码&#xff0c;我们发现&#xff0c;要注意什么&#xff1a; 要分清你的下标Insert 函数是可以用来没有元素的时候&#xff0c;增加元素的Init(或者Create )函数一般只用来分配空间…

Python中如何选择Web开发框架?

Python开发中Web框架可谓是百花齐放&#xff0c;各式各样的web框架层出不穷&#xff0c;那么对于需要进行Python开发的我们来说&#xff0c;如何选择web框架也就变成了一门学问了。本篇文章主要是介绍目前一些比较有特点受欢迎的Web框架&#xff0c;我们可以根据各个Web框架的特…

在线定制印刷系统源码/定制云印刷/个性印刷在线DIY定制商城系统/全站DIV+CSS 布局+手机、PC端

源码简介&#xff1a; 在线定制印刷系统源码/定制云印刷&#xff0c;它是个性印刷在线DIY定制商城系统&#xff0c;而且全站采用DIVCSS 布局&#xff0c;可以手机、PC端实时互通。 支持多种产品定制&#xff0c;包括但不限于水杯、雨伞、U盘、T恤、衬衫和四件套。独创的制作间…

Jenkins与Docker的自动化CI/CD流水线实践

Pipeline 有诸多优点&#xff0c;例如&#xff1a; 项目发布可视化&#xff0c;明确阶段&#xff0c;方便处理问题 一个Jenkins File文件管理整个项目生命周期 Jenkins File可以放到项目代码中版本管理 Jenkins管理界面 操作实例&#xff1a;Pipeline的简单使用 这里是比较…

电源控制系统架构(PCSA)之系统分区电压域

目录 4.1 电压域 4.1.1 系统逻辑 4.1.2 Always-On逻辑 4.1.3 处理器Clusters 4.1.4 图形处理器 4.1.5 其他功能 4.1.6 SoC分区示例 本章描述基于Arm组件的SoC划分为电压域和电源域。 所描述的选择并不详尽&#xff0c;只是可能性的一个子集。目的是描述基于Arm组件的SoC…

MySQL-04-InnoDB存储引擎锁和加锁分析

Latch一般称为闩锁&#xff08;轻量级锁&#xff09;&#xff0c;因为其要求锁定的时间必须非常短。在InnoDB存储引擎中&#xff0c;latch又分为mutex&#xff08;互斥量&#xff09;和rwlock&#xff08;读写锁&#xff09;。 Lock的对象是事务&#xff0c;用来锁定的是…

实验题【网关设置+VRRP+静态路由+OSPF】(H3C模拟器)

嘿&#xff0c;这里是目录&#xff01; ⭐ H3C模拟器资源链接1. 实验示意图2. 要求和考核目标3. 当前配置3.1 PC1、PC2、PC3、PC4和PC5配置3.2 SW配置3.2.1 SW2配置3.2.2 SW3配置3.2.3 SW4配置3.2.4 SW1配置 3.2. R配置3.2.1 R1配置3.2.2 R2配置 ⭐ H3C模拟器资源链接 H3C网络…

Windows下安装MySQL

几年前学习mycat中间件的时候在window机器上安装过MySql&#xff0c;但是由于电脑配置不高&#xff0c;同时打开Mysql服务&#xff0c;idea、SQlyog等软件非常卡&#xff0c;再加上SQLyog和MySQL版本不兼容导致登录不上&#xff0c;于是把它卸载了。最近做练习需要&#xff0c;…

Qt 软件调试(二)使用dump捕获崩溃信息

Qt应用程序异常崩溃该怎么办&#xff0c;生成dump文件再回溯分析&#xff0c;可以快速且准确的帮助我们定位到崩溃的点。那么&#xff0c;本章我们分享下如何在Qt中生成dump文件。 一、使用minudump捕获崩溃信息 #include <QCoreApplication> #include <QDir> #i…

用Python写一个浏览器集群框架

更多Python学习内容&#xff1a;ipengtao.com 在分布式爬虫和大规模数据采集的场景中&#xff0c;使用浏览器集群是一种有效的方式&#xff0c;可以提高数据采集的速度和效率。本文将介绍如何用Python编写一个简单但强大的浏览器集群框架&#xff0c;以应对需要使用多个浏览器实…

原生小程序图表

原生小程序使用图表 话不多说直接进入正题 官方文档: https://www.ucharts.cn/v2/#/ 下载文件 首先去gitee上把文件下载到自己的项目中 https://gitee.com/uCharts/uCharts 找到微信小程序和里面的组件 把里面src下的文件全部下载下来放入自己项目中 项目文件 新建文件…

使用Linux JumpServer堡垒机本地部署与远程访问

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;网络奇遇记、Cpolar杂谈 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. 安装Jump server二. 本地访问jump server三. 安装 cpolar内网穿透软件四. 配…

【面试HOT200】滑动窗口篇

系列综述&#xff1a; &#x1f49e;目的&#xff1a;本系列是个人整理为了秋招面试的&#xff0c;整理期间苛求每个知识点&#xff0c;平衡理解简易度与深入程度。 &#x1f970;来源&#xff1a;材料主要源于【CodeTopHot200】进行的&#xff0c;每个知识点的修正和深入主要参…

linux shell操作 - 05 IO 模型

文章目录 流IO模型阻塞IO非阻塞IOIO多路复用异步IO网络IO模型 流 可以进行IO&#xff08;input输入、output输出&#xff09;操作的内核对象&#xff1b;如文件、管道、socket…流的入口是fd (file descriptor)&#xff1b; IO模型 阻塞IO&#xff0c; 一直等待&#xff0c;…

LLMLingua:集成LlamaIndex,对提示进行压缩,提供大语言模型的高效推理

大型语言模型(llm)的出现刺激了多个领域的创新。但是在思维链(CoT)提示和情境学习(ICL)等策略的驱动下&#xff0c;提示的复杂性不断增加&#xff0c;这给计算带来了挑战。这些冗长的提示需要大量的资源来进行推理&#xff0c;因此需要高效的解决方案&#xff0c;本文将介绍LLM…

分布式篇---第五篇

系列文章目录 文章目录 系列文章目录前言一、你知道哪些限流算法?二、说说什么是计数器(固定窗口)算法三、说说什么是滑动窗口算法前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去…

golang panic关键词执行原理与代码分析

使用的go版本为 go1.21.2 首先我们写一个简单的panic调度与捕获代码 package mainfunc main() {defer func() {recover()}()panic("panic test") }通过go build -gcflags -S main.go获取到对应的汇编代码 可以看到当我们调度panic时&#xff0c;Go的编译器会将这段…

利用Nginx与php处理方式不同绕过Nginx_host实现SQL注入

目录 首先需要搭建环境 nginxphpmysql环境&#xff1a; 搭建网站 FILTER_VALIDATE_EMAIL 绕过 方法1&#xff1a;冒号号分割host字段 方法2&#xff1a;冒号号分割host字段 方法3&#xff1a;SNI扩展绕过 首先需要搭建环境 nginxphpmysql环境&#xff1a; php安装包&a…

具有150KHz固定频率的PWM控制降压型稳压电路芯片D2504,可兼容型号XL4001

D2504是一块具有150KHz固定频率的PWM控制降压型稳压电路&#xff0c;具有高转换效率、2A负 载能力和优异的负载调整率和电压线性度。 主要特点&#xff1a; ● 输入电压范围: 4.5~40V ● 可调输出电压: 1.235~37V ● 最小Drop电压1 5V2A ● 150K 固…

迈巴赫S480升级主动式氛围灯 浪漫婉转的气氛

主动式氛围灯有263个可多色渐变的LED光源&#xff0c;营造出全情沉浸的动态光影氛围。结合智能驾驶辅助系统&#xff0c;可在转向或检测到危险时&#xff0c;予以红色环境光提示&#xff0c;令光影艺术彰显智能魅力。配件有6个氛围灯&#xff0c;1个电脑模块。 1、气候&#xf…