Skip to content

声明式

概述

可以通过注解@ChanceFor和动态代理调用需要重试的函数。具体步骤如下:

  • 抽取需要重试的函数到一个接口类型中,通过@ChanceFor修饰该接口类型或者接口中的方法
  • 通过Chance.newProxy生成接口动态代理实例
  • 通过接口动态代理实例调用具体的方法

WARNING

由于 JDK 只支持基于接口实现的动态代理,这里必须把需要重试函数抽取到接口中定义,@ChanceFor 注解必须应用在接口类型或者接口方法上。

用法详解

新建一个接口:

java
// 应用在接口类上的注解
@ChanceFor(maxRetryTimes = 0)
public interface DeclarativeApi {

    // 此方法会继承接口类上的注解
    String useTypeAnnotation();

    // 应用在接口方法上的注解
    @ChanceFor(maxRetryTimes = 3, include = {RuntimeException.class}, waits = {
            @ChanceFor.WaitFor(type = ChanceFor.WaitType.FIXED, multiplier = 30)
    })
    String useMethodAnnotation();
}

为接口提供一个实现:

java
public class DeclarativeApiImpl implements DeclarativeApi {

    @Override
    public String useTypeAnnotation() {
        return "useTypeAnnotation";
    }

    @Override
    public String useMethodAnnotation() {
        throw new RuntimeException("Error from 'useMethodAnnotation'");
    }
}

生成接口代理实例并且调用对应的方法:

java
public static void main(String[] args) {
    DeclarativeApi declarativeApi = Chance.newProxy(DeclarativeApi.class, new DeclarativeApiImpl());
    String r1 = declarativeApi.useTypeAnnotation();
    System.out.println(r1);
    try {
        String r2 = declarativeApi.useMethodAnnotation();
    } catch (Exception e) {
        // 这里的异常e的类型为UndeclaredThrowableException - 可以参考JDK动态代理中非检查型异常相关问题
        Throwable cause = e.getCause();
        if (cause instanceof ChanceException) {
            ChanceException ce = (ChanceException) cause;
            Attempt<?, ?> lastFailedAttempt = ce.getAttempt();
            System.out.println("Retry times: " + lastFailedAttempt.attemptTimes());
            lastFailedAttempt.rootCauseNow().printStackTrace();
        }
    }
}

上面的代码最终输出结果:

shell
useTypeAnnotation
Retry times: 3
java.lang.RuntimeException: Error from 'useMethodAnnotation'
// ......省略部分异常栈信息......

TIP

注解@ChanceFor 支持的属性可以参考内置条件小节。

注意

基于零依赖的初衷和局限于JDK动态代理,Chance无法天然创建非接口类型的代理,如果更偏好于创建非接口类型的代理可以参考高级特性 - 代理小节。

贡献者

页面历史

Released under the MIT License.