一. 在pom.xml中加入依赖
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
二.@CircuitBreaker
描述:标注需要短路的方法
参数
maxAttempts: 短路执行次数
openTimeout: 短路执行时间
resetTimeout:短路重试时间,当连续两次触发短路时,短路时间=openTimeout+resetTimeout
label:短路器的名字,系统唯一
include:需要短路的异常
exclude:不需要短路的异常
三.@Retryable
描述:标注需要重试的方法
参数
label: 重试的名字,系统唯一
maxAttempts:异常时重试次数
include:需要重试的异常
exclude:不需要重试的异常
四.@Recover
描述: 用来标注二触发短路,三触触发重试失败时,触发的恢复方法。该注解的反法必须和二,三注解的反法在同一个类中,详细见类RecoverAnnotationRecoveryHandler
参数:
标注方法入参: 可以有或者没有,如果有,则是异常时的异常
标注方法返回值: 可替代二或者三失败时返回值
五.示例程序
package com.reger.test.retry;
import java.util.concurrent.TimeUnit;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.CircuitBreaker;
import org.springframework.retry.annotation.EnableRetry;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
@SpringBootApplication
@EnableRetry(proxyTargetClass=true)
public class SpringBootStarterRetryDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootStarterRetryDemoApplication.class, args);
}
@EventListener
public void contextEvent(ContextRefreshedEvent contextEvent) throws InterruptedException {
SpringBootStarterRetryDemoApplication demoApplication=contextEvent.getApplicationContext().getBean(SpringBootStarterRetryDemoApplication.class);
System.err.println("尝试进入断路器方法,并触发异常");
demoApplication.circuitBreaker(1);
demoApplication.circuitBreaker(1);
demoApplication.circuitBreaker(1);
System.err.println("尝试进入断路器方法,在openTimeout时间内,触发异常超过3次,断路器打开,断路器方法不允许执行,直接执行恢复方法");
demoApplication.circuitBreaker(2);
TimeUnit.SECONDS.sleep(2);
System.err.println("超过断路器半开时间resetTimeout,断路器半开,断路器方法运行允许3个访问进入");
demoApplication.circuitBreaker(3);
demoApplication.circuitBreaker(3);
demoApplication.circuitBreaker(3);
System.err.println("尝试进入断路器方法,在openTimeout时间内,触发异常超过3次,断路器打开,断路器方法不允许执行,直接执行恢复方法");
demoApplication.circuitBreaker(4);
TimeUnit.SECONDS.sleep(3);
System.err.println("超过断路器再次超过半开时间openTimeout+resetTimeout,断路器半开,断路器方法运行允许三个访问进入");
demoApplication.circuitBreaker(5);
demoApplication.circuitBreaker(5);
demoApplication.circuitBreaker(5);
System.err.println("尝试进入断路器方法,在openTimeout时间内,触发异常超过3次,断路器打开,断路器方法不允许执行,直接执行恢复方法");
demoApplication.circuitBreaker(6);
TimeUnit.SECONDS.sleep(3);
System.err.println("超过断路器再次超过半开时间openTimeout+resetTimeout,断路器半开,断路器方法运行允许三个访问进入");
demoApplication.circuitBreaker(7);
demoApplication.circuitBreaker(7);
demoApplication.circuitBreaker(7);
System.err.println("尝试进入断路器方法,在openTimeout时间内,触发异常超过3次,断路器打开,断路器方法不允许执行,直接执行恢复方法");
demoApplication.circuitBreaker(8);
TimeUnit.SECONDS.sleep(3);
System.err.println("超过断路器再次超过半开时间openTimeout+resetTimeout,断路器半开,断路器方法运行允许三个访问进入,并且断路方法不再抛出异常,断路器关闭,方法可持续调用");
demoApplication.circuitBreaker(9);
demoApplication.circuitBreaker(9);
demoApplication.circuitBreaker(9);
demoApplication.circuitBreaker(9);
demoApplication.circuitBreaker(9);
demoApplication.circuitBreaker(9);
System.err.println();
System.err.println();
System.err.println("开始重试");
demoApplication.retryable(10);
System.err.println("未抛出异常,");
demoApplication.retryable(11);
}
@CircuitBreaker(maxAttempts=3,openTimeout=1000,resetTimeout=2000,label="test-CircuitBreaker",include=RuntimeException.class,exclude=Exception.class)
public void circuitBreaker(int num) throws InterruptedException {
System.err.print(" 进入断路器方法num="+num);
if(num>8)return;
Integer n=null;
System.err.println(1/n);
}
@Retryable(label="test-Retryable" , maxAttempts=3,backoff=@Backoff(delay=1),include=RuntimeException.class,exclude=Exception.class)
public void retryable(int num) throws InterruptedException {
System.err.println(" 进入重试方法num="+num);
if(num>10)return;
Integer n=null;
System.err.println(1/n);
}
@Recover
public void recover(NullPointerException exception) {
System.err.println(" NullPointerException ....");
}
@Recover
public void recover(RuntimeException exception) {
System.err.println(" RuntimeException ....");
}
@Recover
public void recover(Exception exception) {
System.err.println(" exception ....");
}
@Recover
public void recover(Throwable throwable) {
System.err.println(" throwable ....");
}
@Recover
public void recover() {
System.err.println(" recover ....");
}
}
六.示例输出的日志
尝试进入断路器方法,并触发异常
进入断路器方法num=1 NullPointerException ....
进入断路器方法num=1 NullPointerException ....
进入断路器方法num=1 NullPointerException ....
尝试进入断路器方法,在openTimeout时间内,触发异常超过3次,断路器打开,断路器方法不允许执行,直接执行恢复方法
NullPointerException ....
超过断路器半开时间resetTimeout,断路器半开,断路器方法运行允许3个访问进入
进入断路器方法num=3 NullPointerException ....
进入断路器方法num=3 NullPointerException ....
进入断路器方法num=3 NullPointerException ....
尝试进入断路器方法,在openTimeout时间内,触发异常超过3次,断路器打开,断路器方法不允许执行,直接执行恢复方法
NullPointerException ....
超过断路器再次超过半开时间openTimeout+resetTimeout,断路器半开,断路器方法运行允许三个访问进入
进入断路器方法num=5 NullPointerException ....
进入断路器方法num=5 NullPointerException ....
进入断路器方法num=5 NullPointerException ....
尝试进入断路器方法,在openTimeout时间内,触发异常超过3次,断路器打开,断路器方法不允许执行,直接执行恢复方法
NullPointerException ....
超过断路器再次超过半开时间openTimeout+resetTimeout,断路器半开,断路器方法运行允许三个访问进入
进入断路器方法num=7 NullPointerException ....
进入断路器方法num=7 NullPointerException ....
进入断路器方法num=7 NullPointerException ....
尝试进入断路器方法,在openTimeout时间内,触发异常超过3次,断路器打开,断路器方法不允许执行,直接执行恢复方法
NullPointerException ....
超过断路器再次超过半开时间openTimeout+resetTimeout,断路器半开,断路器方法运行允许三个访问进入,并且断路方法不再抛出异常,断路器关闭,方法可持续调用
进入断路器方法num=9 进入断路器方法num=9 进入断路器方法num=9 进入断路器方法num=9 进入断路器方法num=9 进入断路器方法num=9
开始重试
进入重试方法num=10
进入重试方法num=10
进入重试方法num=10
NullPointerException ....
未抛出异常,
进入重试方法num=11