Karaf中同时引入grpc-context与grpc-api出现NoClassDefFoundError求助
问题描述
- 仅在pom.xml中声明
io.grpc:grpc-context:1.38.0单个依赖时,项目运行无报错 - 额外引入
io.grpc:grpc-api:1.38.0依赖后,启动时抛出java.lang.NoClassDefFoundError: io.grpc.Context异常,底层提示java.lang.ClassNotFoundException: io.grpc.Context无法被org.opendaylight类加载器加载 - 已确认grpc-api本身传递依赖grpc-context,尝试添加exclusion规则排除冲突未解决
相关配置
依赖配置
<dependency> <groupId>io.grpc</groupId> <artifactId>grpc-context</artifactId> <version>1.38.0</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-api</artifactId> <version>1.38.0</version> </dependency>
Karaf包导出查询结果
执行package:exports -p io.grpc命令查询io.grpc包导出情况,结果如下:
opendaylight-user@root>package:exports -p io.grpc io.grpc 0.0.0 354 wrap_file__home_verizon_gnmi_gnmi_karaf_target_assembly_system_io_grpc_grpc-api_1.38.0_grpc-api-1.38.0.jar io.grpc 0.0.0 355 wrap_file__home_verizon_gnmi_gnmi_karaf_target_assembly_system_io_grpc_grpc-context_1.38.0_grpc-context-1.38.0.jar opendaylight-user@root>package:exports -d io.grpc 0.0.0 354 355
根因说明
这是Karaf(OSGi容器)典型的同包多导出冲突问题:io.grpc包同时被ID为354的grpc-api bundle和ID为355的grpc-context bundle导出,且两个导出的包版本都被识别为0.0.0,OSGi类加载器无法确定优先加载哪个bundle下的类,最终导致核心类加载失败。
解决方案
方案1:删除重复的显式依赖
grpc-api本身已经传递依赖grpc-context,不需要单独声明grpc-context依赖,直接删除pom文件中grpc-context的显式引入,仅保留grpc-api依赖即可,避免两个jar同时被打包为独立bundle部署到Karaf。
方案2:显式指定包导入规则
在项目的maven-bundle-plugin配置中,显式指定io.grpc包的导入版本,绑定到正确的依赖,配置示例如下:
<plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <configuration> <instructions> <Import-Package> io.grpc;version="1.38.0", * </Import-Package> <Export-Package> !io.grpc.*, * </Export-Package> </instructions> </configuration> </plugin>
同时可以给grpc相关依赖添加正确的OSGi manifest配置,避免包版本被识别为0.0.0。
方案3:合并gRPC相关依赖为单个bundle
使用maven-shade-plugin将grpc-api、grpc-context等所有gRPC相关依赖打包为一个单独的自定义bundle,统一导出io.grpc包,从根源避免多bundle同包导出的冲突。
方案4:调整Karaf类加载优先级
在Karaf的etc/config.properties文件中配置org.osgi.framework.system.packages.extra参数,指定优先导入的io.grpc包来源,或者部署时先部署grpc-api bundle,再部署其他依赖gRPC的业务bundle,保证优先生效的是grpc-api导出的io.grpc包。
内容的提问来源于stack exchange,提问作者Vinoth

