Skip to content

代理

概述

指南 - 声明式小节中已经介绍了基于JDK动态代理的声明式使用,如果更偏好于对非接口类型的代理使用,可以额外引入CGLIB依赖。例如:

xml
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>

Chance本身是零依赖设计,但是已经基于provided类型的scope引入了CGLIB并且为非接口类型代理提供了实现。

使用详解

在同时引入CGLIB依赖和Chance依赖到前提下,添加一个非接口类ChanceApi

java
// 应用在类上的注解
@ChanceFor(maxRetryTimes = 0)
public class ChanceApi {

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

    // 应用在方法上的注解
    @ChanceFor(maxRetryTimes = 3, include = {RuntimeException.class}, waits = {
            @ChanceFor.WaitFor(type = ChanceFor.WaitType.FIXED, multiplier = 30)
    })
    public String useMethodAnnotation() {
        throw new RuntimeException("Error from 'useMethodAnnotation'");
    }
}

生成动态代理并且调用对应的方法:

java
public static void main(String[] args) throws Exception {
    ChanceApi chanceApi = Chance.newProxy(ChanceApi.class, new ChanceApi());
    String typeResult = chanceApi.useTypeAnnotation();
    System.out.println("typeResult: " + typeResult);
    try {
        chanceApi.useMethodAnnotation();
    } catch (Exception e) {
        // 这里的异常e的类型为ChanceException - 和JDK动态代理调用的场景有所不同
        if (e instanceof ChanceException) {
            ChanceException ce = (ChanceException) e;
            Attempt<?, ?> lastFailedAttempt = ce.getAttempt();
            System.out.println("Retry times: " + lastFailedAttempt.attemptTimes());
            lastFailedAttempt.rootCauseNow().printStackTrace();
        }
    }
}

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

shell
typeResult: useTypeAnnotation
Retry times: 3
java.lang.RuntimeException: Error from 'useMethodAnnotation'
// ......省略异常堆栈......

使用CGLIB生成的代理调用对应的方法如果抛出异常,那么捕获的异常就是抛出的异常实例本身,这一点跟JDK原生的动态代理有点不同。JDK动态代理在调用对应的方法时候如果方法内部抛出异常,该异常会被包装为UndeclaredThrowableException抛出。

贡献者

页面历史

Released under the MIT License.