21

以下代码不会重试。我错过了什么?

@EnableRetry
@SpringBootApplication
public class App implements CommandLineRunner
{
    .........
    .........


    @Retryable()
    ResponseEntity<String> authenticate(RestTemplate restTemplate, HttpEntity<MultiValueMap<String, String>> entity) throws Exception
    {
        System.out.println("try!");
        throw new Exception();
        //return restTemplate.exchange(auth_endpoint, HttpMethod.POST, entity, String.class);
    }

我在 pom.xml 中添加了以下内容。

    <dependency>
        <groupId>org.springframework.retry</groupId>
        <artifactId>spring-retry</artifactId>
        <version>1.1.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>

我还尝试为@Retryable 提供不同的参数组合。

@Retryable(maxAttempts=10,value=Exception.class,backoff=@Backoff(delay = 2000,multiplier=2))

谢谢。

4

9 回答 9

33

在 spring boot 2.0.2 Release 中,我观察到@Retryable如果您在同一个类中有可重试和调用的方法,则该方法不起作用。在调试时发现切入点没有正确构建。目前,这个问题的解决方法是我们需要在不同的类中编写方法并调用它。

工作示例可以在这里找到。

于 2018-06-27T12:37:00.720 回答
14

要发现方法上的@Retryable注释,需要从初始化的上下文中正确调用它。该方法是从spring上下文中的bean调用还是通过其他方式调用?

如果测试这是你的跑步者使用SpringJunit4ClassRunner

于 2016-07-08T10:51:42.930 回答
8

我解决了。我发现如果从您尝试重试的方法中返回某些内容,则 @Retryable() 不起作用。

pom.xml 中的 maven 依赖项

    <dependency>
        <groupId>org.springframework.retry</groupId>
        <artifactId>spring-retry</artifactId>
        <version>1.1.5.RELEASE</version>
    </dependency>

春季启动应用程序.java

@SpringBootApplication
@EnableTransactionManagement
@EnableRetry
public class Application {

     public static void main(String[] args) throws Exception {
       SpringApplication.run(Application.class, args);
     }

}

在控制器.java

@RestController
public class JavaAllDataTypeController {

@Autowired
JavaAllDataTypeService JavaAllDataTypeService;


@RequestMapping(
        value = "/springReTryTest",
        method = RequestMethod.GET
)
public ResponseEntity<String> springReTryTest() {

    System.out.println("springReTryTest controller");

    try {
         JavaAllDataTypeService.springReTryTest();
    } catch (Exception e) {
        e.printStackTrace();
    }

    return new  ResponseEntity<String>("abcd", HttpStatus.OK);
  }

}

在 service.java 中

@Service
@Transactional
public class JavaAllDataTypeService {

 // try the method 9 times with 2 seconds delay.
 @Retryable(maxAttempts=9,value=Exception.class,backoff=@Backoff(delay = 2000))
 public void springReTryTest() throws Exception {

    System.out.println("try!");
    throw new Exception();
  }

}

输出:它尝试了 9 次然后抛出异常。

在此处输入图像描述

于 2016-12-18T09:12:15.593 回答
3

它也适用于返回类型

@Service
public class RetryService {

private int count = 0;

// try the method 9 times with 2 seconds delay.
@Retryable(maxAttempts = 9, value = Exception.class, backoff = @Backoff(delay = 2000))
public String springReTryTest() throws Exception {
    count++;
    System.out.println("try!");

    if (count < 4)
        throw new Exception();
    else
        return "bla";
  }

}
于 2018-03-12T13:22:57.093 回答
3

我遇到了与原始问题中描述的完全相同的问题。

在我的情况下,结果发现spring-boot-starter-aop依赖项被意外地不包括在内。将其添加到 my 后pom.xml,我的@Retryable方法按预期工作。

从方法返回值@Retryable对我来说很好。

于 2019-05-13T13:29:44.607 回答
1

对于那些想@Retryable在同一个班级调用块的人可以这样。

这里的关键是不要直接通过自注入bean调用方法

@Slf4j
@Service
public class RetryService {

    @Resource(name = "retryService")
    private RetryService self;

    public String getValue(String appender) {
        return self.getData(appender);
    }

    @Retryable(value = NumberFormatException.class, maxAttempts = 4, backoff = @Backoff(500))
    public String getData(String appender) {
        log.info("Calling getData");
        Integer value = Integer.parseInt(appender);
        value++;
        return value.toString();
    }

    @Recover
    public String recoverData(String appender) {
        log.info("Calling recoverData");
        return "DEFAULT";
    }

}

可以在此处详细阅读有关使用重试的更多信息

于 2021-05-07T07:50:58.763 回答
0

另一种可能是RetryTemplate

@Bean
    public RetryTemplate retryTemplate() {
        RetryTemplate retryTemplate = new RetryTemplate();

        FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
        fixedBackOffPolicy.setBackOffPeriod(2000l);
        retryTemplate.setBackOffPolicy(fixedBackOffPolicy);

        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
        retryPolicy.setMaxAttempts(2);
        retryTemplate.setRetryPolicy(retryPolicy);

        return retryTemplate;
    }

retryTemplate.execute(new RetryCallback<Void, RuntimeException>() {
    @Override
    public Void doWithRetry(RetryContext arg0) {
        myService.templateRetryService();
        ...
    }
});

为我解决了

资源

于 2019-02-21T14:36:32.883 回答
0

Spring 的@Retryable、@Cacheable、@Transaction 等都是使用面向切面编程实现的。Spring 通过基于代理的编织实现 AOP。代理拦截从一个 bean 到另一个 bean 的调用。代理不能拦截从一个对象的方法到另一个对象的调用。这是基于代理的编织的一般限制。

以下解决方案解决了这个限制:1)如上所述,使用@Autowired(或@Resource)注入一个带有自引用的bean;对该引用的调用通过代理。2) 使用 AspectJ 的 ClassLoader 而不是 Spring 默认的基于代理的编织。3) 如上所述,将方法放在单独的 bean 上。我在各种情况下都做过,每个都有优点和缺点。

于 2022-03-02T16:51:10.000 回答
0

甚至我也遇到了同样的问题,后来经过一番调查研究才知道,除了方法上面的@Retryable注解,我们还需要在类上面提供@EnableRetry。这个@EnableRetry 注释可以在您提供要重试的方法的同一类之上提供,也可以在您的主要 Spring Boot 应用程序类之上提供。例如像这样:

@RequiredArgsConstructor
**@EnableRetry**
@Service
public class SomeService {

  **@Retryable(value = { HttpServerErrorException.class, BadRequestException.class},
      maxAttempts = maxRetry, backoff = @Backoff(random = true, delay = 1000,
                         maxDelay = 8000, multiplier = 2))**
  public <T> T get( ) throws  HttpServerErrorException, BadRequestException {
    
     //write code here which you want to retry
  }

}

我希望这将有助于解决您的问题。

于 2021-02-20T12:12:35.847 回答