dubbo升级遇到问题
近期对@Reference修饰的consumer接口进行设置超时时间,之前所用dubbo版本是2.6.5
遇到问题是想对具体方法设置超时时间。xml配置有个<method> 可设置,现项目Springboot 配置注解化了,以前的xml此处就不说明了。
开始找的方法是在 @Reference 注解的 param下添加参数
parameters = {"searchExerciseRelevant.timeout", "10", "searchExerciseByDrawers.timeout", "10"}
@ignore(10ms 是方便测试下是否有效)
dubbo导出服务的时候就是把这些配置拼到组成的url链接上,在invoke的时候会取相应的参数取做处理,此处直接拼上去即可解决问题。
后来查看dubbo github上版本,2.6.6之后的版本已经加上了 methods参数,于是升级了下dubbo版本。最终配置成如下
@Reference(timeout = 1200000,
methods = {@Method(name = "searchExerciseRelevant", timeout = 10000),
@Method(name = "searchExerciseByDrawers", timeout = 10000)}
)
代码是配置好了,但是在启动的时候发现项目起不来了.
问题1
java.lang.IllegalStateException: Invalid name="com.alibaba.dubbo.config.ProtocolConfig#0" contains illegal character, only digit, letter, '-', '_' or '.' is legal
大致意思就是设置名字不合法
找了找解决方法是给dubbo.protocol.name 设置个名字,
protocol:
port: 20919
name: dubbo
经查看代码为啥会有名字不合法,问题出在com.alibaba.dubbo.config.spring.context.config.NamePropertyDefaultValueDubboConfigBeanCustomizer#customize方法上,这个类的这个方法意思是如果有name属性 且存在get set 方法,参数是string,但name属性的值为空时,会给设置个名字,此处取beanName作为name属性名称。ProtocolConfig 是通过springBean起名的方式获取的,具体方法com.alibaba.dubbo.config.spring.context.annotation.DubboConfigBindingRegistrar#resolveSingleBeanName
private String resolveSingleBeanName(Map<String, Object> properties, Class<? extends AbstractConfig> configClass,
BeanDefinitionRegistry registry) {
String beanName = (String) properties.get("id");
if (!StringUtils.hasText(beanName)) {
BeanDefinitionBuilder builder = rootBeanDefinition(configClass);
beanName = BeanDefinitionReaderUtils.generateBeanName(builder.getRawBeanDefinition(), registry);
}
return beanName;
}
BeanDefinitionReaderUtils.generateBeanName 返回的beanname是带#的。
customize 方法在执行setName的时候会调用父类AbstractConfig的checkName方法,对name值做检测抛出异常。
private static final Pattern PATTERN_NAME = Pattern.compile("[\\-._0-9a-zA-Z]+");
protected static void checkName(String property, String value) {
checkProperty(property, value, MAX_LENGTH, PATTERN_NAME);
}
protected static void checkProperty(String property, String value, int maxlength, Pattern pattern) {
if (value == null || value.length() == 0) {
return;
}
if (value.length() > maxlength) {
throw new IllegalStateException("Invalid " + property + "=\"" + value + "\" is longer than " + maxlength);
}
if (pattern != null) {
Matcher matcher = pattern.matcher(value);
if (!matcher.matches()) {
throw new IllegalStateException("Invalid " + property + "=\"" + value + "\" contains illegal " +
"character, only digit, letter, '-', '_' or '.' is legal.");
}
}
}
问题2
The bean 'dubboConfigConfiguration.Single', defined in null, could not be registered. A bean with that name has already been defined in null and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
按提示设置allow-bean-definition-overriding=true 报错可解决
main:
allow-bean-definition-overriding: true
2.6.5之前是使用 DubboConfigConfigurationSelector 实现ImportSelector 返回类名称去加载的
2.6.8是使用 DubboConfigConfigurationRegistrar 实现ImportBeanDefinitionRegistrar 使用Spring工具类注
册加载的
为什么会重复注册呢,跟进代码发现由于上面2个类的实现区别和@EnableDubboConfig 的默认值为true导致。
Springboot集成dubbo DubboAutoConfiguration类里定义了2个@EnableDubboConfig修饰的内部类,分别代表单配置和多配置,根据这个注解,分别去注册相对应的bean
在版本2.6.5 @EnableDubboConfig 的multiple 的默认属性为false
DubboConfigConfigurationSelector 代码中对muliple 为true和false时分别只注册一个bean
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName()));
boolean multiple = attributes.getBoolean("multiple");
if (multiple) {
return of(DubboConfigConfiguration.Multiple.class.getName());
} else {
return of(DubboConfigConfiguration.Single.class.getName());
}
}
在版本2.6.8 @EnableDubboConfig 的multiple 的默认属性为true
DubboConfigConfigurationRegistrar 代码就有点意思了,默认注册单配置的bean,根据multiple参数去注册多配置的bean
public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName()));
boolean multiple = attributes.getBoolean("multiple");
// Single Config Bindings
registerBeans(registry, DubboConfigConfiguration.Single.class);
if (multiple) { // Since 2.6.6 https://github.com/apache/incubator-dubbo/issues/3193
registerBeans(registry, DubboConfigConfiguration.Multiple.class);
}
}
}
根据目前的DubboAutoConfiguration,会执行2次此逻辑,bean会重复注册,所以Spring会报错提示。
后来升级了dubbo 2.7.4.1 在这个版本 @EnableDubboConfig注解是放在@EnableDubbo 注解上,DubboConfigConfigurationRegistrar的逻辑只会执行一次,不用配置Spring覆盖为true也没事。
相对应的版本Springboot集成dubbo的boot-start jar包中的 DubboAutoConfiguration 采用了@Import 直接导入bean
本次dubbo使用问题分析到此,有疑问可留言,继续更新😄