Spring Boot gRPC Server初始化错误:无法获取NettyServerProvider无参构造方法
Java 17 Spring Boot自定义gRPC Server配置遇到ServiceConfigurationError问题
问题描述
我在Java 17的Spring Boot应用中手动配置gRPC Server时,实例化服务器触发了如下错误。
自定义配置代码
package org.xenwgram.config; import io.grpc.Grpc; import io.grpc.InsecureServerCredentials; import io.grpc.Server; import io.grpc.ServerCredentials; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.xenwgram.service.Impl.MessageServiceImpl; import java.io.IOException; import java.util.concurrent.TimeUnit; @Configuration public class GrpcServerConfig { @Bean public Server grpcServer() { try { Server server = Grpc.newServerBuilderForPort(6565, InsecureServerCredentials.create()) .build(); server.start(); Runtime.getRuntime().addShutdownHook(new Thread(() -> { try { server.shutdown().awaitTermination(30, TimeUnit.SECONDS); } catch (InterruptedException e) { e.printStackTrace(); } })); return server; } catch (IOException e) { throw new RuntimeException("Failed to start gRPC server", e); } } }
build.gradle.kts依赖配置
plugins { id("java") id("com.google.protobuf") version "0.9.4" id("io.spring.dependency-management") version "1.1.6" id("org.springframework.boot") version "2.7.16" } group = "org.xenwgram" version = "v0.0.1" repositories { mavenLocal() mavenCentral() maven("https://gitlab.com/api/v4/projects/65346162/packages/maven") } dependencies { testImplementation(platform("org.junit:junit-bom:5.10.0")) testImplementation("org.junit.jupiter:junit-jupiter") implementation("org.xenwgram:xengram-proto:test-1.1") // Spring Boot starter web implementation("org.springframework.boot:spring-boot-starter-web:3.4.0") // Lombok for compile-time code generation compileOnly("org.projectlombok:lombok") annotationProcessor("org.projectlombok:lombok") implementation("org.projectlombok:lombok-mapstruct-binding:0.1.0") // gRPC Spring Boot starter implementation("net.devh:grpc-server-spring-boot-starter:3.1.0.RELEASE") // gRPC dependencies implementation("io.grpc:grpc-netty-shaded:1.69.0") implementation("io.grpc:grpc-protobuf:1.69.0") implementation("io.grpc:grpc-stub:1.69.0") // Google Protocol Buffers implementation("com.google.protobuf:protobuf-java:4.29.1") } tasks.test { useJUnitPlatform() }
错误信息
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'grpcServer' defined in class path resource [org/xenwgram/config/GrpcServerConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [io.grpc.Server]: Factory method 'grpcServer' threw exception; nested exception is java.util.ServiceConfigurationError: io.grpc.ServerProvider: io.grpc.netty.NettyServerProvider Unable to get public no-arg constructor
已尝试操作
- 使用grpc-server-spring-boot-starter自动配置时运行正常;
- 使用上述自定义配置时触发错误。
疑问
- 为何会出现NettyServerProvider的ServiceConfigurationError?
- 我的gRPC Server配置是否存在问题?
- 是否应该切换为Spring Boot starter的自动配置?
解答
1. 为何出现NettyServerProvider的ServiceConfigurationError?
核心原因是依赖冲突与类加载问题:
- 你同时引入了
grpc-netty-shaded和grpc-server-spring-boot-starter,starter内部已经包含非shaded版的Netty gRPC依赖,shaded包会重命名Netty相关类,导致gRPC的ServiceLoader无法找到正确的NettyServerProvider类(原始类名已被修改),进而抛出"无法获取无参构造"的错误。 - Spring Boot版本不一致:你用的Spring Boot核心版本是2.7.16,但
spring-boot-starter-web用了3.4.0,跨大版本的依赖会导致整个依赖树混乱,间接引发类加载异常。
2. 自定义gRPC Server配置的问题
你的配置存在多处问题:
- 版本不兼容:
spring-boot-starter-web版本3.4.0与Spring Boot核心2.7.16严重不兼容,破坏了Spring的依赖管理逻辑。 - 服务未注册:手动构建Server时没有添加
MessageServiceImpl服务实现,即便启动成功也无法处理任何gRPC请求。 - 生命周期管理错误:在Bean初始化阶段直接调用
server.start(),此时Spring上下文尚未完全初始化,可能导致后续依赖该Server的Bean出现异常;手动添加shutdown hook也不符合Spring的生命周期管理规范。 - 重复配置冲突:
grpc-server-spring-boot-starter已经会自动创建gRPC Server Bean,手动创建的Bean会与自动配置的Bean产生冲突。
3. 是否应该切换为Spring Boot starter的自动配置?
优先推荐使用grpc-server-spring-boot-starter的自动配置,理由如下:
- 它已经封装了gRPC Server的生命周期管理(自动启动、优雅关闭),无需手动编写shutdown hook和启动逻辑。
- 自动处理依赖冲突、类加载问题,避免手动配置时的版本兼容坑。
- 提供Spring Boot风格的配置项(如通过
application.yml修改gRPC端口、启用TLS等),与Spring生态无缝集成。 - 如需自定义,可通过添加
ServerBuilderCustomizerBean来扩展Server配置,无需完全手动实现。
如果坚持手动配置,需要做以下调整:
- 移除
grpc-server-spring-boot-starter依赖,避免冲突。 - 统一Spring Boot版本:将
spring-boot-starter-web改为2.7.16,与核心版本一致。 - 在ServerBuilder中注册服务:
.addService(new MessageServiceImpl())。 - 调整启动时机:使用
@PostConstruct注解在Bean初始化完成后启动Server,而非在Bean创建阶段直接启动。
内容的提问来源于stack exchange,提问作者xenwithu
相关产品推荐
相关产品推荐

