Java 为Spring引导控制器调用的特定方法设置超时

Java 为Spring引导控制器调用的特定方法设置超时,java,spring-boot,Java,Spring Boot,我在我的SpringBootAPI中有这个路由,它应该接收一个注册表对象,尝试将它保存到DB并通知它是否成功。这是我的控制器的方法: @POST @Path( "/save" ) public Response save( @RequestBody Registry registry ) { Response validatedResponse = validateRegistry( registry ); if ( isErrorResponse( va

我在我的SpringBootAPI中有这个路由,它应该接收一个注册表对象,尝试将它保存到DB并通知它是否成功。这是我的控制器的方法:

@POST
@Path( "/save" )
public Response save( @RequestBody Registry registry ) {

    Response validatedResponse = validateRegistry( registry );

    if ( isErrorResponse( validatedResponse ) )
        return validatedResponse;

    try {
        return ResponseBuilder.success( this.registryRepository.save( registry ) );
    } catch ( Exception e ) {
        LOGGER.error( "Error while trying to save", e );
        return ResponseBuilder.failure( "error at /save" );
    }
}
validateRegistry
如下所示:

private Response validateRegistry( Registry registry ) {

    // some trivial validation on the Registry object's fields        
    
    Optional< Connection > connection;

    try {
        connection = connectionService.findById( registry.getConnectionIdentifier() );
        registryService.setConnection( connection.get() );
        try {
            return registryService.doesRegistryExists( registry );
        } catch ( Exception e ) {
            LOGGER.failure( "error at /save (validation)" );
            LOGGER.failure( e.getMessage() );
        }
    } catch ( Exception e ) {
        return ResponseBuilder.failure( "not able to retrieve connection for given registry ");
    }
    
        return ResponseBuilder.success();
}
private Response validateRegistry(注册表){
//注册表对象字段上的一些琐碎验证
可选<连接>连接;
试一试{
connection=connectionService.findById(registry.getConnectionIdentifier());
registryService.setConnection(connection.get());
试一试{
返回registryService.doesRegistryExists(注册表);
}捕获(例外e){
LOGGER.failure(“保存(验证)时出错”);
LOGGER.failure(如getMessage());
}
}捕获(例外e){
返回ResponseBuilder.failure(“无法检索给定注册表的连接”);
}
返回ResponseBuilder.success();
}
验证的一部分包括验证是否存在相同的注册表,如您所见,我从调用方检索连接以访问其基础并搜索注册表-这就是
registryService.doesRegistryExists
所做的。现在,我想将执行
doesRegistryExists
的时间限制在几秒钟之内,因为有时执行查询需要花费太多的时间-中止执行是可以的,因为我可以返回一个描述情况的响应并要求稍后再试


我该怎么办?我曾尝试使用ExecutorService包装查询调用方,但它会导致调用方抛出NullPointerException。

使用
ExecutorService
是一个很好的解决方案,您可以通过提交并等待一定时间的结果来获得

private ExecutorService executorService = Executors.newFixedThreadPool(10);

private Response validateRegistry( Registry registry ) {
  ...
  try {
    Callable<Response> task = () -> registryService.doesRegistryExists(registry);
    Future<Response> future = executorService.submit(task);
    // wait for the result for at most 2 seconds
    return future.get(2, TimeUnit.SECONDS);
  } catch (TimeoutException e) {
    // handle the timeout exception here
  } catch (Exception e) {
    // handle the other exceptions here        
  }
  ... 
}
private ExecutorService ExecutorService=Executors.newFixedThreadPool(10);
专用响应验证注册表(注册表){
...
试一试{
可调用任务=()->registryService.doesRegistryExists(注册表);
Future=executorService.submit(任务);
//等待结果最多2秒钟
返回future.get(2,TimeUnit.SECONDS);
}捕获(超时异常e){
//在这里处理超时异常
}捕获(例外e){
//在这里处理其他异常
}
... 
}

如果连接和数据库都有超时,那么将连接本身设置为超时,而不是将其包装到另一个项目中是有意义的。另外,因为您使用的是spring boot,所以您可以使用@Transactional(timeout=5)的注释来设置5秒的超时时间,这也是有道理的,但不幸的是,我无法更改连接类,只是尝试了@Transactional(timeout=5)注释,但是,当查询执行器或其调用者在可调用的内部执行时,它抛出一个NullPointerException
NullPointerException
的原因是什么?它只说“java.lang.Exception:java.lang.NullPointerException”,没有堆栈跟踪