湖南做电商网站需要什么条件,中铁中基建设集团网站,qq是用什么软件开发的,廊坊做网站的企业哪家好原创/朱季谦
首先#xff0c;先提一个建议#xff0c;在SpringBootDubbo项目中#xff0c;Dubbo配置注册中心设置的application命名name的值#xff0c;最好使用xxx-xxx-xxx这样格式的#xff0c;避免随便使用驼峰命名。因为使用驼峰命名法#xff0c;在Spring的IOC容器…
原创/朱季谦
首先先提一个建议在SpringBootDubbo项目中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.xDubbo项目当中主流都是使用yaml文件设置项目环境依赖参数不同的组件其配置类的实例化各有差异。
Dubbo初始化配置类主要有以下——
序号类名用途说明1ApplicationConfig当前应用配置提供者或者消费者配置当前应用信息一般以属性name区分各应用2MonitorConfig监控中心配置配置连接监控中心monitor参数3RegistryConfig连接注册中心配置配置Dubbo用到的注册中心4ProtocolConfig服务提供者协议配置配置提供方的远程通信协议........................
这些配置类的实现原理基本大同小异本文主要以ApplicationConfig配置类做讲解分析。
在yaml配置文件里Dubbo的配置例子如下——
dubbo:application:name: userServiceregistry:address: zookeeper://127.0.0.1:2181timeout: 10000protocol:name: dubboport: 20880这个配置可以拆开如下图这样看便能一眼看懂它们分别属于哪个配置类—— 当在yaml文件这样配置后当项目启动时会自动获取这些参数然后初始化到对应的配置类当中例如application中的name值就会设置到ApplicationConfig类对象里—— 在SpringBoot中这个ApplicationConfig对象会在普通bean初始化之前就已经装载到IOC容器当中以name的值做该bean名同时会以name:className的方式存储在Spring的bean别名缓存aliasMap当中这就出现一个问题假如该项目当中存在同名bean注解的话会出现什么样情况呢
例如当SpringBoot的Dubbo配置如前边一样以字符串“userService”做ApplicationConfig的name值同时controller层有以下代码——
RestController
RequestMapping(/user)
public class UserController {Resourceprivate UserService userService;......
}我们可以在IOC容器过程的AbstractBeanFactory类中的doGetBean(String name, Nullable Class requiredType, Nullable Object[] args, boolean typeCheckOnly)方法截图处打一个针对userService的断点—— 截图里的逻辑其实是在对注解有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获取是可以拿到值的—— 但是这里注意一点此刻debug这一步doGetBean理应依赖注入的是UserService类而不是ApplicationConfig类—— 然而实际情况是此时通过方法Object sharedInstance getSingleton(beanName)从IOC三级缓存之一的单例池里获取到的则是ApplicationConfig已经初始化成单例bean的对象—— 这将会出现什么情况呢
在 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这样方式命名会更好些。