Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/379.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 看到异步的意外行为并重试spring引导_Java_Spring Boot_Asynchronous_Threadpool_Spring Retry - Fatal编程技术网

Java 看到异步的意外行为并重试spring引导

Java 看到异步的意外行为并重试spring引导,java,spring-boot,asynchronous,threadpool,spring-retry,Java,Spring Boot,Asynchronous,Threadpool,Spring Retry,我有一个并行调用多个RESTAPI的用例。但这里的关键是,他们需要在每个请求的头中传递一个访问令牌。所以,我最终制作了这个类级别变量。在超时或令牌过期的情况下也会发生重试。在令牌过期的情况下,我们调用loadToken()方法获取新令牌,然后重试相同的调用。我们最多重试3次 问题: 我看到的一个问题是loadToken()可以由多个线程同时调用,这里可能存在争用条件 在珠三角,我看到了非常奇怪的行为。即使出现500个错误,重试也会触发loadToken()方法,这是不应该发生的。如果令牌过期,则

我有一个并行调用多个RESTAPI的用例。但这里的关键是,他们需要在每个请求的头中传递一个访问令牌。所以,我最终制作了这个类级别变量。在超时或令牌过期的情况下也会发生重试。在令牌过期的情况下,我们调用loadToken()方法获取新令牌,然后重试相同的调用。我们最多重试3次

问题:

  • 我看到的一个问题是loadToken()可以由多个线程同时调用,这里可能存在争用条件
  • 在珠三角,我看到了非常奇怪的行为。即使出现500个错误,重试也会触发loadToken()方法,这是不应该发生的。如果令牌过期,则只应触发loadToken()
  • 这里有任何改进此代码的想法/建议。谢谢你的帮助

    代码如下所示:

    @组件
    公共类MyDaoImpl实现MyDao{
    @自动连线
    私有RestTemplate RestTemplate;
    私有字符串令牌;
    @施工后
    public void loadToken()引发CustomException{
    HttpHeaders=新的HttpHeaders();
    headers.setContentType(MediaType.APPLICATION\u FORM\u URLENCODED);
    MultiValueMap=新链接的MultiValueMap();
    HttpEntity请求=新的HttpEntity(映射、头);
    试一试{
    ResponseEntity exchange=restemplate.exchange(tokenUrl、HttpMethod.POST、request、TokenResponse.class);
    token=exchange.getBody()!=null&&StringUtils.isNotBlank(exchange.getBody().getToken())?exchange.getBody().getToken():null;
    }捕获(例外e){
    投掷e;
    }
    }
    @凌驾
    @异步(“线程池执行器”)
    @可重试(MaxAttemptsPression=“#${retry.max.attempts:3}}”,值={UnAuthorizedException.class,GatewayTimeoutException.class},退避=@backoff(delayExpression=“#${retry.backoff.period:1000}”))
    公共CompletableFuture getResponse1(字符串)引发CustomException{
    HttpHeaders=新的HttpHeaders();
    setBearerAuth(getAccessToken());
    HttpEntity请求=新的HttpEntity(标头);
    试一试{
    ResponseEntity exchange=restemplate.exchange(url,HttpMethod.GET,请求,字节[].class);
    if(exchange.getBody()==null)返回CompletableFuture.completedFuture(null);
    返回CompletableFuture.completedFuture(Base64.getEncoder().encodeToString(exchange.getBody());
    }捕获(HttpClientErrorException | HttpServerErrorException e){
    如果(例如getStatusCode()==HttpStatus.UNAUTHORIZED){
    loadToken();
    抛出新的UnAuthorizedException(“过期令牌”,e);
    }
    }捕获(例外e){
    if(StringUtils.isNotEmpty(e.getMessage())和&(e.getMessage().contains(“上的I/O错误”)| | e.getMessage()contains(“超时”)){
    抛出新的GatewayTimeoutException(“网关超时”,e);
    }
    }
    返回CompletableFuture.completedFuture(空);
    }
    @凌驾
    @异步(“线程池执行器”)
    @可重试(MaxAttemptsPression=“#${retry.max.attempts:3}}”,值={UnAuthorizedException.class,GatewayTimeoutException.class},退避=@backoff(delayExpression=“#${retry.backoff.period:1000}”))
    公共CompletableFuture getResponse2(字符串)引发CustomException{
    HttpHeaders=新的HttpHeaders();
    setBearerAuth(getAccessToken());
    HttpEntity请求=新的HttpEntity(标头);
    试一试{
    final ResponseEntity exchange=restemplate.exchange(someurl,HttpMethod.GET,request,Response.class);
    返回CompletableFuture.completedFuture(exchange.getBody());
    }捕获(HttpClientErrorException | HttpServerErrorException e){
    如果(例如getStatusCode()==HttpStatus.UNAUTHORIZED){
    loadToken();
    抛出新的UnAuthorizedException(“过期令牌”,e);
    }
    }捕获(例外e){
    if(StringUtils.isNotEmpty(e.getMessage())和&(e.getMessage().contains(“上的I/O错误”)| | e.getMessage()contains(“超时”)){
    抛出新的GatewayTimeoutException(“网关超时”,e);
    }
    }
    返回CompletableFuture.completedFuture(空);
    }
    @凌驾
    公共字符串getAccessToken()引发异常{
    if(StringUtils.isBlank(令牌)){
    loadToken();
    }
    返回令牌;
    }
    @凌驾
    @异步(“线程池执行器”)
    @可重试(MaxAttemptsPression=“#${retry.max.attempts:3}}”,值={UnAuthorizedException.class,GatewayTimeoutException.class},退避=@backoff(delayExpression=“#${retry.backoff.period:1000}”))
    公共CompletableFuture getResponse3(字符串字符串)引发CustomException{
    HttpHeaders=新的HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    setBearerAuth(getAccessToken());
    HttpEntity请求=新的HttpEntity(“{}”,标头);
    试一试{
    ResponseEntity exchange=restemplate.exchange(someUrl2,HttpMethod.POST,request,新参数化类型引用(){});
    返回CompletableFuture.completedFuture(exchange.getBody());
    }捕获(HttpClientErrorException | HttpServerErrorException e){
    如果(例如getStatusCode()==HttpStatus.UNAUTHORIZED){
    loadToken();
    抛出新的UnAuthorizedException(“过期令牌”,e);
    }
    }捕获(例外e){
    if(StringUtils.isNotEmpty(e.getMessage())和&(e.getMessage().contains(“上的I/O错误”)| | e.getMessage()contains(“超时”)){
    抛出新的GatewayTimeoutException(“网关超时”,e);
    }
    }
    返回CompletableFuture.completedFuture(空);
    }
    @凌驾
    @异步(“线程池执行器”)
    @可重试(maxAttemptsExpression=“#{${retry.ma