创建GRPC ManagedChannel时遇io.grpc.Channel类加载约束冲突求助
解决IntelliJ插件项目中GRPC客户端类加载冲突问题
我在Kotlin开发的IntelliJ插件项目中搭建GRPC客户端,用于调用Nvidia Triton推理服务器(23.06-py3版本)。已通过Gradle配置Protoc代码生成,但创建ManagedChannel并初始化Coroutine Stub时出现运行时错误:
问题代码片段
val channel = ManagedChannelBuilder.forTarget("127.0.0.1:8001") .usePlainText() .build() val inferenceStub = GRPCInferenceServiceGrpcKt.GRPCInferenceServiceCoroutineStub(channel) val modelLive = inferenceStub.modelReady( GrpcService.ModelReadyRequest.newBuilder() .setName("santacoder_huggingface") .build() )
首次错误日志
2023-11-17 15:11:36,839 [ 9708] ERROR - pplication.impl.LaterInvocator - loader constraint violation: loader com.intellij.util.lang.UrlClassLoader @174d20a wants to load abstract class io.grpc.Channel. A different abstract class with the same name was previously loaded by com.intellij.ide.plugins.cl.PluginClassLoader @6404ea6d. (io.grpc.Channel is in unnamed module of loader com.intellij.ide.plugins.cl.PluginClassLoader @6404ea6d, parent loader 'bootstrap') java.lang.LinkageError: loader constraint violation: loader com.intellij.util.lang.UrlClassLoader @174d20a wants to load abstract class io.grpc.Channel. A different abstract class with the same name was previously loaded by com.intellij.ide.plugins.cl.PluginClassLoader @6404ea6d. (io.grpc.Channel is in unnamed module of loader com.intellij.ide.plugins.cl.PluginClassLoader @6404ea6d, parent loader 'bootstrap')
替换依赖后的新错误
尝试将grpc-netty-shaded替换为grpc-netty或移除依赖后,出现:
2023-11-17 15:25:48,470 [ 7696] ERROR - pplication.impl.LaterInvocator - io.grpc.ManagedChannelProvider: io.grpc.netty.shaded.io.grpc.netty.NettyChannelProvider not a subtype java.util.ServiceConfigurationError: io.grpc.ManagedChannelProvider: io.grpc.netty.shaded.io.grpc.netty.NettyChannelProvider not a subtype
项目核心Gradle配置
plugins { id("java") alias(libs.plugins.kotlin) alias(libs.plugins.gradleIntelliJPlugin) alias(libs.plugins.changelog) alias(libs.plugins.qodana) id("com.google.protobuf") version "0.9.4" }
解决方案
1. 排除IntelliJ自带GRPC依赖,统一项目依赖版本
IntelliJ平台自身集成了GRPC相关类,会和项目依赖产生类加载冲突。需要在Gradle中排除宿主环境的GRPC依赖,并强制使用项目指定版本:
// 在intellij配置块中排除自带GRPC组件 intellij { version.set("2023.1") // 你的IntelliJ版本 type.set("IC") // 社区版/旗舰版 plugins.set(listOf()) excludePlugins("io.grpc") } dependencies { // 指定统一的GRPC依赖版本 val grpcVersion = "1.59.0" val grpcKotlinVersion = "1.4.0" implementation("io.grpc:grpc-netty-shaded:$grpcVersion") implementation("io.grpc:grpc-protobuf:$grpcVersion") implementation("io.grpc:grpc-kotlin-stub:$grpcKotlinVersion") implementation("com.google.protobuf:protobuf-kotlin:3.24.3") // 全局排除宿主环境的GRPC/Protobuf传递依赖 configurations.all { exclude(group = "io.grpc") exclude(group = "com.google.protobuf") } }
2. 使用Shadow插件重命名GRPC/Netty包(彻底隔离冲突)
通过Shadow插件将项目中的GRPC和Netty类重命名为自定义前缀,从根本上避免类名冲突:
首先添加Shadow插件:
plugins { // 其他插件... id("com.github.johnrengelman.shadow") version "7.1.2" }
配置重命名规则:
shadowJar { // 重命名GRPC包到自定义前缀 relocate("io.grpc", "your.plugin.id.grpc") // 重命名Netty包(解决shaded依赖的类冲突) relocate("io.netty", "your.plugin.id.netty") // 可选:重命名Protobuf包 relocate("com.google.protobuf", "your.plugin.id.protobuf") } // 让IntelliJ插件使用Shadow打包后的Jar intellij { // 其他配置... shadowJar.set(true) }
3. 手动指定ChannelProvider避免服务加载错误
如果出现ServiceConfigurationError,可以跳过SPI自动加载,手动指定ChannelProvider:
import io.grpc.netty.shaded.io.grpc.netty.NettyChannelProvider // 创建Channel时手动指定Provider val channel = ManagedChannelBuilder.forTarget("127.0.0.1:8001") .usePlainText() .channelProvider(NettyChannelProvider()) .build()
原因说明
- LinkageError:IntelliJ插件类加载器和项目类加载器分别加载了
io.grpc.Channel类的不同版本,JVM判定为两个不同类,导致约束冲突。 - ServiceConfigurationError:SPI加载的ChannelProvider来自不同类加载器,类型不匹配;
grpc-netty-shaded的Provider位于io.grpc.netty.shaded包下,而非默认的io.grpc.netty包,需手动指定或确保SPI配置正确。
内容的提问来源于stack exchange,提问作者Ayush Vachaspati
相关产品推荐
相关产品推荐

