Spring Retry重试框架的应用

95 篇文章 3 订阅
60 篇文章 2 订阅

环境:SpringBoot2.4.3 + Spring Retry + JPA + MySQL + JDK8


  • 相关依赖
<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>

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

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>
  • 配置文件
spring:
  datasource:
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/testjpa?serverTimezone=GMT%2B8&useSSL=false
    username: root
    password: ******
    type: com.zaxxer.hikari.HikariDataSource
    hikari:
      minimumIdle: 10
      maximumPoolSize: 200
      autoCommit: true
      idleTimeout: 30000
      poolName: MasterDatabookHikariCP
      maxLifetime: 1800000
      connectionTimeout: 30000
      connectionTestQuery: SELECT 1
  • 实体类及DAO
@Entity
@Table(name = "t_account")
public class Account {
    @Id
    private Long id;
    private String userId;
    private BigDecimal money;
}
public interface AccountDAO extends JpaRepository<Account, Long> {

    Account findByUserId(String userId);

}
  • Service类
@Service
public class AccountService {
	
	@Resource
	private AccountDAO accountDAO ;
	
	@Transactional
	@Retryable(value = {InvalidParameterException.class})
	public Account save(Account account) {
		System.out.println(Thread.currentThread().getName()) ;
		if (account.getId() == 0) {
			System.out.println("save retry...") ;
			throw new InvalidParameterException("无效参数") ;
		}
		return accountDAO.saveAndFlush(account) ;
	}
  // 当重试了指定的次数后将会回调此方法
	@Recover
    public Account recoverSave(Exception e) {
		System.out.println("............." + e.getMessage()) ;
		return null ;
    }
	
}

@Retryable注解说明:

  • recover:指定兜底/补偿的方法名。如果不指定,默认对照 @Recover 标识的,第一入参为重试异常,其余入参和出参一致的方法;这里是通过@Recover注解对照指定。
  • interceptor:指定方法切面 bean,org.aopalliance.intercept.MethodInterceptor 实现类
  • value / include:可重试的异常类型,如果value和include都为空,那么会对所有的异常进行重试;
  • exclude:和 include 相反,指出哪些异常不需要重试;
  • label:可以指定唯一标签,用于统计;
  • stateful:默认false。重试是否是有状态的;
  • maxAttempts:最大的重试次数,默认为3;
  • backoff:指定 @Backoff,回退策略;@Backoff属性如下:

Spring Retry重试框架的应用

 

这里可以指定重试的策略,比如:延迟多久进行重试。

  • listeners:监听器,指定 org.springframework.retry.RetryListener 实现 bean。下面有示例演示。

开启重试功能@EnableRetry

@Configuration
@EnableRetry
public class RetryConfig {
	
}

测试:

@Resource
	private AccountService accountService ;
	
	@Test
	public void testSave() {
		Account account = new Account() ;
		account.setId(0L) ;
		account.setMoney(BigDecimal.valueOf(1000)) ;
		account.setUserId("1") ;
		
		accountService.save(account) ;
	}

控制台输出:

Spring Retry重试框架的应用

 

默认进行了3次重试。


@Retryable注解属性listeners的使用

@Retryable(value = {InvalidParameterException.class}, stateful = false, listeners = {"accountRetryListener"})

定义监听器:

public class AccountRetryListener implements RetryListener {

	@Override
	public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
		System.out.println("open invoke...") ;
		return false;
	}

	@Override
	public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback,
			Throwable throwable) {
		System.out.println("close invoke...") ;
	}

	@Override
	public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback,
			Throwable throwable) {
		System.out.println("onError invoke...") ;
		throwable.getStackTrace() ;
	}

}

这里的open方法如果返回false,那么将不会进行重试。

执行结果:

Spring Retry重试框架的应用

 

 


基于编程式重试

自定义RetryTemplate

@Configuration
@EnableRetry
public class RetryConfig {
	
	@Bean
	public RetryTemplate retryTemplate() {
		RetryTemplate template = RetryTemplate.builder()
				.maxAttempts(3) // 重试次数
				.fixedBackoff(1000) // 以固定的时间间隔重试(1000ms)
				.retryOn(InvalidParameterException.class) // 当发生InvalidParameterException异常时进行重试
				.build();
		return template ;
	}
	
}
public class AccountService {
	
	@Resource
	private AccountDAO accountDAO ;
	@Resource
	private RetryTemplate retryTemplate ;
	
	@Transactional
	public Account update(Account account) {
		return retryTemplate.execute(context -> {
			if (account.getId() == 0) {
				System.out.println("update retry...") ;
				throw new InvalidParameterException("无效参数") ;
			}
			return accountDAO.saveAndFlush(account) ;
		}, context -> {
      System.out.println("重试结束...") ;
			return null ;
		}) ;
	}
	
}

测试:

@Test
	public void testUpdate() {
		Account account = new Account() ;
		account.setId(0L) ;
		account.setMoney(BigDecimal.valueOf(1000)) ;
		account.setUserId("1") ;
		
		accountService.update(account) ;
	}

执行结果

Spring Retry重试框架的应用

 

完毕!!!

给个关注+转发呗,谢谢

ElasticSearch使用Java API调用相关服务

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值