You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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:

  1. 给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();
        // ... 业务逻辑
    }
}
  1. 在测试类中注入该服务实例并使用:
@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管理,可以在测试类中手动给它的依赖赋值:

  1. 给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();
        // ... 业务逻辑
    }
}
  1. 在测试类中手动注入依赖:
@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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 16:37:52