Spring Boot中使用Spring-Retry重试框架

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Boot中使用Spring-Retry重试框架相关的知识,希望对你有一定的参考价值。

参考技术A 在启动类中使用@EnableRetry注解

需要在重试的代码中加入重试注解 @Retryable

默认情况下,会重试3次,间隔1秒

我们可以从注解 @Retryable 中看到

我们来运行测试代码

运行结果如下:

可以看到重新执行了3次 service1() 方法,然后间隔是1秒,然后最后还是重试失败,所以抛出了异常

既然我们看到了注解 @Retryable 中有这么多参数可以设置,那我们就来介绍几个常用的配置。

首先是 maxAttempts ,用于设置重试次数

从运行结果可以看到,方法执行了5次。

下面来介绍 maxAttemptsExpression 的设置

maxAttemptsExpression 则可以使用表达式,比如上述就是通过获取配置中maxAttempts的值,我们可以在application.yml设置。上述其实省略掉了SpEL表达式 #.... ,运行结果的话可以发现方法执行了4次..

我们可以使用SpEL表达式

接着我们下面来看看 exceptionExpression , 一样也是写SpEL表达式

上面的表达式 exceptionExpression = "message.contains('test')" 的作用其实是获取到抛出来exception的message(调用了 getMessage() 方法),然后判断message的内容里面是否包含了 test 字符串,如果包含的话就会执行重试。所以如果调用方法的时候传入的参数 exceptionMessage 中包含了 test 字符串的话就会执行重试。

但这里值得注意的是, Spring Retry 1.2.5之后 exceptionExpression 是可以省略掉 #...

使用1.2.5之后的版本运行是没有问题的

但是如果使用1.2.5版本之前包括1.2.5版本的话,运行的时候会报错如下:

还可以在表达式中执行一个方法,前提是方法的类在spring容器中注册了, @retryService 其实就是获取bean name为 retryService 的bean,然后调用里面的 checkException 方法,传入的参数为 #root ,它其实就是抛出来的exception对象。一样的也是可以省略 #...

运行结果:

当然还有更多表达式的用法了...

下面再来看看另一个配置 exclude

这个 exclude 属性可以帮我们排除一些我们不想重试的异常

最后我们来看看这个 backoff 重试等待策略, 默认使用 @Backoff 注解。

我们先来看看这个 @Backoff 的 value 属性,用于设置重试间隔

运行结果可以看出来重试的间隔为2秒

接下来介绍 @Backoff 的 delay 属性,它与 value 属性不能共存,当 delay 不设置的时候会去读 value 属性设置的值,如果 delay 设置的话则会忽略 value 属性

运行结果可以看出,重试的时间间隔为500ms

接下来我们来看``@Backoff 的 multiplier`的属性, 指定延迟倍数, 默认为0。

multiplier 设置为2,则表示第一次重试间隔为2s,第二次为4秒,第三次为8s

运行结果如下:

接下来我们来看看这个 @Backoff 的 maxDelay 属性,设置最大的重试间隔,当超过这个最大的重试间隔的时候,重试的间隔就等于 maxDelay 的值

运行结果:

可以最后的最大重试间隔是5秒

当 @Retryable 方法重试失败之后,最后就会调用 @Recover 方法。用于 @Retryable 失败时的“兜底”处理方法。 @Recover 的方法必须要与 @Retryable 注解的方法保持一致,第一入参为要重试的异常,其他参数与 @Retryable 保持一致,返回值也要一样,否则无法执行!

测试方法

运行结果:

可以看到这些配置跟我们直接写注解的方式是差不多的,这里就不过多的介绍了。。

RetryOperations 定义重试的API, RetryTemplate 是API的模板模式实现,实现了重试和熔断。提供的API如下:

下面主要介绍一下RetryTemplate配置的时候,需要设置的重试策略和退避策略

RetryPolicy是一个接口, 然后有很多具体的实现,我们先来看看它的接口中定义了什么方法

我们来看看他有什么具体的实现类

看一下退避策略,退避是指怎么去做下一次的重试,在这里其实就是等待多长时间。

listener可以监听重试,并执行对应的回调方法

使用如下:

自定义一个Listener

把listener设置到retryTemplate中

测试结果:

原文链接:Spring Retry 在SpringBoot 中的应用 - ityml - 博客园

Spring boot中使用jwt

spring boot 使用 jwt

本文旨在介绍如何在spring boot中使用jwt,不会介绍什么是jwt

一、导入依赖

1. spring-boot依赖

<!--父依赖-->
<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.2.6.RELEASE</version>
	<relativePath/> 
</parent>


<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.junit.jupiter</groupId>
                <artifactId>junit-jupiter-api</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

2. jwt 依赖

<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.4.0</version>
</dependency>

二、应用

创建一个JwtUtil文件

package cn.edu.swpu.news.util;

import cn.edu.swpu.news.entity.User;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;

import java.time.*;
import java.util.HashMap;
import java.util.Map;

/**
 * jwt工具类
 * @author ycwiacb 2020/5/2
 */
@Slf4j
public class JwtUtil {

    //这里填写你自己自定义的SECRET
    private static final String SECRET = "ycwiacb-secret";

    /**生成token*/
    public static String sign(User user) {
        Algorithm algorithm = Algorithm.HMAC256(SECRET);
        Map<String, Object> map = new HashMap<>(16);
        map.put("alg", "HS256");
        map.put("typ", "JWT");
        return JWT.create().withHeader(map)
                .withClaim("userId", user.getId())
                .withClaim("username", user.getUsername())
                .withIssuer("ycwiacb")
                .withIssuedAt(DateUtil.localDateTimeToDate(LocalDateTime.now()))
                .withExpiresAt(DateUtil.localDateTimeToDate(LocalDateTime.now().plusMinutes(30)))
                .sign(algorithm);
    }

    /**验证token并返回id*/
    public static Long verify(String token) {
        long userId = 0L;
        try {
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            JWTVerifier jwtVerifier = JWT.require(algorithm)
                    .withIssuer("ycwiacb")
                    .build();
            DecodedJWT decodedjwt = jwtVerifier.verify(token);
            userId = decodedjwt.getClaim("userId").asLong();
        } catch (JWTVerificationException e) {
            log.error("解析token失败, exception = {}", e.toString());
        }
        return userId;
    }
}

注意:这里使用的是decodedjwt.getClaim("userId").asLong(); 这里是asLong(),对应的有asString(),而非toString()

附上DateUtil文件

package cn.edu.swpu.news.util;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;

/**
 * @author ycwiacb 2020/5/5
 */
public class DateUtil {

    /**
     *将LocalDateTime 时间类转化为Date
     * @return Date
     */
    public static Date localDateTimeToDate(LocalDateTime dateTime) {
        return Date.from(dateTime.atZone(ZoneId.of("Asia/Shanghai")).toInstant());
    }
}

测试,JwtUtilTest.java

package cn.edu.swpu.news.util;

import cn.edu.swpu.news.entity.User;
import org.junit.Test;

/**
 * @author ycwiacb 2020/5/10
 */
public class JwtUtilTest {

    @Test
    public void sign() {
        User user = new User();
        user.setId(1L);
        user.setUsername("testUserName");
        System.out.println("测试jwt:token = " + JwtUtil.sign(user));
    }

    @Test
    public void verify() {
        String token = "你生成的token";
        System.out.println("解析token:userId=" + JwtUtil.verify(token));
    }
}

测试结果:

技术图片

技术图片

以上就是对jwt的基本操作,具体请看文档

三、参考文档

java-jwt : https://github.com/auth0/java-jwt

以上是关于Spring Boot中使用Spring-Retry重试框架的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot:Spring Boot 中 MongoDB 的使用

Spring Boot:在Spring Boot中使用Mysql和JPA

Spring boot- Spring Boot特性2

使用 Spring Boot Maven 插件时,jar 文件中缺少 Spring Boot 应用程序中的资源

Spring boot中使用jwt

Spring boot中使用jwt