🎀dubbo 2.7.2 启动报错【Unsupported generic type false】排查

💖1.问题现象

dubbo服务启动时抛出异常Unsupported generic type false,但不影响服务正常发布。

Caused by: java.lang.IllegalArgumentException: Unsupported generic type false

📖2. 版本信息

SpringBoot 2.1.3 + Dubbo 2.7.2

👉3. 问题根因

项目中使用了Spring Boot Actuator模块,Spring Boot Actuator配置独立的管理端口时会创建特殊子上下文(项目中会存在两个上下文实例),导致dubbospring上下文刷新事件监控触发两次;
同时开启了dubbo延迟发布(dubbo.provider.delay=3000),由于dubbo 2.7.2中的BUG,两次均会进行了export动作;
同时由于dubbo 2.7.2版本中对generic的判断问题而在第二次export时抛出异常。

⭐4.分析过程

message中可以看出:Unsupported generic type falsedubbo 泛化调用配置错误告警


🌟4.1. 检查配置是否有误

检查全局中dubbo配置是否存在generic="false"

<dubbo:service generic="false" />

经过检查,项目中无该问题配置

🌟4.2. 堆栈分析

通过检查未发现人为错误配置,进一步分析异常堆栈
具体堆栈如下:

level: ERRORthreadName: mainclassName: o.a.d.c.AbstractConfig - [DUBBO] Failed to override , dubbo version: 2.7.2, current host: xxx.xxx.xxx.xxx
java.lang.reflect.InvocationTargetException: null
        at sun.reflect.GeneratedMethodAccessor864.invoke(Unknown Source) ~[?:?]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_412]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_412]
        at org.apache.dubbo.config.AbstractConfig.refresh(AbstractConfig.java:567) ~[dubbo-2.7.2.jar!/:2.7.2]
        at org.apache.dubbo.config.ServiceConfig.checkAndUpdateSubConfigs(ServiceConfig.java:304) ~[dubbo-2.7.2.jar!/:2.7.2]
        at org.apache.dubbo.config.ServiceConfig.export(ServiceConfig.java:369) ~[dubbo-2.7.2.jar!/:2.7.2]
        at org.apache.dubbo.config.spring.ServiceBean.export(ServiceBean.java:336) ~[dubbo-2.7.2.jar!/:2.7.2]
        at org.apache.dubbo.config.spring.ServiceBean.onApplicationEvent(ServiceBean.java:114) ~[dubbo-2.7.2.jar!/:2.7.2]
        at org.apache.dubbo.config.spring.ServiceBean.onApplicationEvent(ServiceBean.java:60) ~[dubbo-2.7.2.jar!/:2.7.2]
        at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172) ~[spring-context-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
        at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165) ~[spring-context-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
        at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) ~[spring-context-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:402) ~[spring-context-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:359) ~[spring-context-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:896) ~[spring-context-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.finishRefresh(ServletWebServerApplicationContext.java:163) ~[spring-boot-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:552) ~[spring-context-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142) ~[spring-boot-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) ~[spring-boot-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) ~[spring-boot-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) ~[spring-boot-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) ~[spring-boot-2.1.3.RELEASE.jar!/:2.1.3.RELEASE]
        at com.xxx.xxx.xxx.xxx.xxxApiStartUp.main(xxxApiStartUp.java:26) ~[classes!/:?]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_412]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_412]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_412]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_412]
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48) ~[xxx.jar:?]
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:87) ~[xxx.jar:?]
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:50) ~[xxx.jar:?]
        at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51) ~[xxx.jar:?]
Caused by: java.lang.IllegalArgumentException: Unsupported generic type false
        at org.apache.dubbo.config.ServiceConfig.setGeneric(ServiceConfig.java:1015) ~[dubbo-2.7.2.jar!/:2.7.2]

从堆栈上可以看出在ServiceBean这里有对spring事件的监控
查看源码如下:

可以看出dubbo是在spring ApplicationContext 上下文刷新时进行了发布动作export

这里引起思考:为什么实际dubbo服务没有发布失败了?

🌟4.3. 官方issues

前往github检索官方可发现有相同的issues
https://github.com/apache/dubbo/issues/3629

🌟4.4. 源码分析

为什么export两次ServiceConfig会有问题了?

再回到dubbo源码,可以发现在export中有对generic赋默认值false的动作;
在第一次refresh后进行赋值,在第二次refresh时由于generic="false"报错

然而这里并没有结束

在前面duubo serviceBean spring上下文刷新事件的监控源码中可以看到,dubbo有对重复发布的屏蔽处理动作

那为什么还能发布两次了?

继续看该发布属性的更新可知,是在serviceConfig doExport之后更新

往上寻找调用栈可以发现:在dubbo export时有两种发布模式:直接发布、延迟发布

看过dubbo源码的同学可以看出,直接发布模式下,应该会被发布属性拦截

可以看出异步发布模式下,第一次异步发布后,第二次上下文刷新事件监控进入时发布属性会无法拦截

前往配置中心也可以看到有相关延迟发布的配置

dubbo.provider.delay=3000

到这里我们取消了延迟发布后,重启后不再报错。


虽然表象问题解决,但根本原因是为什么会触发两次发布动作了?

看源码这里是对spring ApplicationContext上下文刷新事件的监控,触发两次说明有两个个上下文实例。
可以写个工具检测输出下:

@Component
public class ContextRefreshCounter implements ApplicationListener<ContextRefreshedEvent> {
    private static int count = 0;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        System.out.println("Context refreshed, total times: " + ++count);
        System.out.println("ApplicationContext instance: " + System.identityHashCode(event.getApplicationContext()));
        System.out.println("ApplicationContext id: " + event.getApplicationContext().getId());
    }
}

看到有两个上下文:applicationapplication:management

application是根上下文
application:managementSpring Boot Actuator 管理端点的子上下文

查看配置中心,发现有配置独立的管理端口

management.server.port=8081

由此可知由于引入了Spring Boot Actuator且配置了独立的管理端口,导致生成多个上下文实例,从而触发了多次spring上下文刷新事件的监控。

⭐5. 官方修复

后续版本官方已针对generic值的判断以及dubbo服务发布逻辑进行了优化,具体可前往github官网查看。
https://github.com/apache/dubbo


结束

posted @ 2025-01-26 11:35  丿似锦  阅读(36)  评论(0)    收藏  举报