Spring Retry retry framework

Introduction

Spring Retry source address

The Spring Retry retry framework supports both declarative and imperative usage.

Environmental requirements

Spring Retry requires Java 1.7 and Maven 3.0.5 (or greater). It is
recommended that Java 1.8 and above be used to simplify the code using lambda expressions.

Declarative

Declarative usage is based on AOP aspect programming, which requires the introduction of aspectjweaver or spring-boot-starter-aop
pom.xml

	<!-- Spring Retry -->
	<dependency>
	    <groupId>org.springframework.retry</groupId>
	    <artifactId>spring-retry</artifactId>
	</dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
@Configuration
@EnableRetry
public class Application {
    
    

}

@Service
class Service {
    
    
    @Retryable(RemoteAccessException.class)
    public void service() {
    
    
        // ... do something
    }
    @Recover
    public void recover(RemoteAccessException e) {
    
    
       // ... panic
    }
}

actual case:

    @Override
    @Retryable(value = {
    
     Exception.class }, maxAttempts = 3, backoff = @Backoff(delay = 5000L, multiplier = 1))
    public Object restPostTest(Map map, String url) throws Exception {
    
    
        logger.info("调用第三方接口");
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        //设置访问的Entity
        HttpEntity entity = new HttpEntity<>(map, headers);
        ResponseEntity<String> result;
        JSONObject data = new JSONObject();
        //发起一个POST请求
        logger.info("发起一个POST请求");
        result = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
        data = JSONObject.parseObject(result.getBody());
        logger.info("返回结果{}",data);
        return data;
    }
    
    @Recover
    public Object recover(Exception e, Map map, String url) {
    
    
       // ... 放入消息队列或数据库
    }

@Retryable Annotation The
annotated method will be retried
when an exception occurs. Value: Specify the occurrence of the exception to retry.
Include: Same as value, empty by default. When exclude is also empty, all exceptions are retried.
Exclude: Specify the exception to not retry. , Default is empty, when include is also empty, all exceptions are retried
maxAttemps: number of retries, default 3
backoff: retry compensation mechanism, default no

@Backoff annotation
delay: Retry after the specified delay
multiplier: Specify the multiple of the delay, such as delay=5000l, multiplier=2, the first retry is 5 seconds, the second time is 10 seconds, and the third time is 20 seconds

@Recover
When the retries reach the specified number of times, the annotated method will be called back, and log processing can be performed in this method. It should be noted that the callback will only occur when the exception occurs and the input parameter type is the same.

Description:

  • The class object where the above annotations are located must be taken over by the spring container, using @Service, @Bean, etc.
  • @Retryable and @Recover marked method return values ​​must be consistent!
  • @Recover method parameter, Exception e must be placed in the first parameter position and the type must be consistent with the type thrown by @Retryable.
  • Try...catch can no longer be used in @Retryable methods to catch exceptions to prevent exceptions from being unreceived.

Programmatic (imperative)

RetryTemplate template = new RetryTemplate();

TimeoutRetryPolicy policy = new TimeoutRetryPolicy();
policy.setTimeout(30000L);

template.setRetryPolicy(policy);

Foo result = template.execute(new RetryCallback<Foo>() {
    
    

    public Foo doWithRetry(RetryContext context) {
    
    
        // Do stuff that might fail, e.g. webservice operation
        return result;
    }

});

Chained usage combined with lambda expression to simplify code

RetryTemplate template = RetryTemplate.builder()
				.maxAttempts(3)
				.fixedBackoff(1000)
				.retryOn(RemoteAccessException.class)
				.build();

template.execute(ctx -> {
    
    
    // ... do something
});

The lambda part does not rewrite the logic of RetryCallback#doWithRetry.

public interface RetryCallback<T> {
    
    

    T doWithRetry(RetryContext context) throws Throwable;

}

Listener:

public interface RetryListener {
    
    

    void open(RetryContext context, RetryCallback<T> callback);

    void onError(RetryContext context, RetryCallback<T> callback, Throwable e);

    void close(RetryContext context, RetryCallback<T> callback, Throwable e);
}

template.registerListener(new MethodInvocationRetryListenerSupport() {
    
    
      @Override
      protected <T, E extends Throwable> void doClose(RetryContext context,
          MethodInvocationRetryCallback<T, E> callback, Throwable throwable) {
    
    
        monitoringTags.put(labelTagName, callback.getLabel());
        Method method = callback.getInvocation()
            .getMethod();
        monitoringTags.put(classTagName,
            method.getDeclaringClass().getSimpleName());
        monitoringTags.put(methodTagName, method.getName());

        // register a monitoring counter with appropriate tags
        // ...
      }
    });

Guess you like

Origin blog.csdn.net/ory001/article/details/108546494