使用GrpcCleanupRule进行gRPC测试时依赖注入失效问题求助
gRPC测试中服务类依赖注入为null的解决方法
问题场景
测试类SaveTest中通过@Autowired注入的FileUtils能正常使用,但手动new GrpcStorageServiceImpl()添加到gRPC服务时,服务类内部的@Resource注入的FileUtil为null。而另一项测试中直接@Autowired注入的SseServiceImpl里的RedisUtil却能正常工作。
测试类核心代码
@RunWith(SpringRunner.class) @SpringBootTest public class SaveTest { @Rule public final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule(); @Autowired private FileUtils fileUtils; @Test public void saveGrpcTest() throws IOException { String serverName = InProcessServerBuilder.generateName(); // 手动new的服务类,导致内部依赖无法被Spring注入 grpcCleanup.register(InProcessServerBuilder .forName(serverName).directExecutor().addService(new GrpcStorageServiceImpl()).build().start()); StorageServiceGrpc.StorageServiceBlockingStub blockingStub = StorageServiceGrpc.newBlockingStub( grpcCleanup.register(InProcessChannelBuilder.forName(serverName).directExecutor().build())); StorageReply reply = blockingStub.saveHfm(PersistentHfmRequest.newBuilder() .setUserId(USER_ID) .setProjectId(PROJECT_ID) .setTaskId(TASK_ID) .setElementId(ELEMENT_ID) .setLightPathId(LIGHT_PATH_ID_08) .build()); assertEquals("Hello test name", reply.getMessage()); } }
gRPC服务类代码
public class GrpcStorageServiceImpl extends StorageServiceGrpc.StorageServiceImplBase { @Resource private FileUtils fileUtil; @Override public void save(PersistentHfmRequest request, StreamObserver<StorageReply> responseObserver) { // fileUtil为null,调用会抛出空指针异常 String filePath = fileUtil.getFilePath(); // ... 业务逻辑 } }
原因分析
- 手动
new GrpcStorageServiceImpl()创建的对象不属于Spring容器管理,Spring无法自动处理其中的@Resource/@Autowired依赖注入。 SseServiceImpl是通过@Autowired从Spring容器中获取的实例,所有依赖已被Spring初始化完成,因此RedisUtil能正常使用。
解决方法
方法1:从Spring容器获取gRPC服务实例(推荐)
让GrpcStorageServiceImpl被Spring管理,然后在测试类中注入该实例,而非手动new:
- 给gRPC服务类添加Spring组件注解(如
@Service):
@Service public class GrpcStorageServiceImpl extends StorageServiceGrpc.StorageServiceImplBase { @Resource private FileUtils fileUtil; @Override public void save(PersistentHfmRequest request, StreamObserver<StorageReply> responseObserver) { String filePath = fileUtil.getFilePath(); // ... 业务逻辑 } }
- 在测试类中注入该服务实例并使用:
@RunWith(SpringRunner.class) @SpringBootTest public class SaveTest { @Rule public final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule(); @Autowired private FileUtils fileUtils; // 注入Spring管理的gRPC服务实例 @Autowired private GrpcStorageServiceImpl storageService; @Test public void saveGrpcTest() throws IOException { String serverName = InProcessServerBuilder.generateName(); // 使用Spring注入的实例,内部依赖已完成注入 grpcCleanup.register(InProcessServerBuilder .forName(serverName).directExecutor().addService(storageService).build().start()); StorageServiceGrpc.StorageServiceBlockingStub blockingStub = StorageServiceGrpc.newBlockingStub( grpcCleanup.register(InProcessChannelBuilder.forName(serverName).directExecutor().build())); // ... 后续请求代码 } }
方法2:手动注入依赖(应急方案)
如果无法让GrpcStorageServiceImpl被Spring管理,可以在测试类中手动给它的依赖赋值:
- 给gRPC服务类添加setter方法:
public class GrpcStorageServiceImpl extends StorageServiceGrpc.StorageServiceImplBase { @Resource private FileUtils fileUtil; // 添加setter方法用于手动注入 public void setFileUtil(FileUtils fileUtil) { this.fileUtil = fileUtil; } @Override public void save(PersistentHfmRequest request, StreamObserver<StorageReply> responseObserver) { String filePath = fileUtil.getFilePath(); // ... 业务逻辑 } }
- 在测试类中手动注入依赖:
@Test public void saveGrpcTest() throws IOException { String serverName = InProcessServerBuilder.generateName(); GrpcStorageServiceImpl storageService = new GrpcStorageServiceImpl(); // 手动注入fileUtil storageService.setFileUtil(fileUtils); grpcCleanup.register(InProcessServerBuilder .forName(serverName).directExecutor().addService(storageService).build().start()); // ... 后续请求代码 }
方法3:使用Spring集成的gRPC测试支持
如果项目使用spring-boot-starter-grpc等集成包,可直接利用Spring管理的gRPC服务进行测试,无需手动构建InProcessServer:
@RunWith(SpringRunner.class) @SpringBootTest public class SaveTest { // 通过@GrpcClient注解注入gRPC stub @GrpcClient("storage-service") private StorageServiceBlockingStub blockingStub; @Autowired private FileUtils fileUtils; @Test public void saveGrpcTest() throws IOException { StorageReply reply = blockingStub.saveHfm(PersistentHfmRequest.newBuilder() .setUserId(USER_ID) .setProjectId(PROJECT_ID) .setTaskId(TASK_ID) .setElementId(ELEMENT_ID) .setLightPathId(LIGHT_PATH_ID_08) .build()); assertEquals("Hello test name", reply.getMessage()); } }
这种方式下,gRPC服务由Spring自动启动和管理,所有依赖注入都会正常工作。
内容的提问来源于stack exchange,提问作者luffyxue
相关产品推荐
相关产品推荐

