Java 的动态代理是基于静态代理演化而来的,所以我们先看看静态代理

1 静态代理

静态代理就是对原来对象的包装,通过实现相同的接口来达到这个效果

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/** 定义一个接口 */
public interface IUserDao {
    void save();
}

/** 实现一个实现类 */
public class UserDaoImpl implements IUserDao {
    @Override
    public void save() {
        System.out.println("实际执行逻辑");
    }
}

/** 静态代理对象 */
public class UserDaoProxy implements IUserDao {
    private IUserDao target;
    public UserDaoProxy(IUserDao target) {
        this.target = target;
    }

    @Override
    public void save() {
        System.out.println("Before advice");
        try {
            // 执行目标对象方法
            target.save();
            System.out.println("After returning advice");
        } catch (Exception e) {
            System.out.println("After throwing advice");
            throw e;
        } finally {
            System.out.println("Finally advice");
        }
    }
}

/** 测试效果 */
public class Main {
    public static void main(String[] args) {
        UserDaoImpl target = new UserDaoImpl();
        // 输出原对象信息
        System.out.println(String.format("origin class: [%s]", target.getClass()));
        UserDaoProxy userDaoProxy = new UserDaoProxy(target);
        // 输出代理对象信息
        System.out.println(String.format("proxy class: [%s]", userDaoProxy.getClass()));
        // 执行代理方法
        userDaoProxy.save();
    }
}

输出
// 实际的对象
origin class: [class me.yuanzx.demo.proxy.jdk.UserDaoImpl]
// 包装出的代理对象
proxy class: [class me.yuanzx.demo.proxy.jdk.wrapper.UserDaoProxy]
Before advice
实际执行逻辑
After returning ad

2 动态代理

Java 的动态代理模式依靠 java.lang.reflect.Proxy 类来实现,下面是一个例子

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/** 定义一个接口 */
public interface IUserDao {
    void save();
}

/** 实现一个实现类 */
public class UserDaoImpl implements IUserDao {
    @Override
    public void save() {
        System.out.println("实际执行逻辑");
    }
}

/** 动态代理类实现工厂 */
public class ProxyFactory <T> {

    /** 维护一个目标对象 */
    private T target;

    public ProxyFactory(T target) {
        this.target = target;
    }

    /** 为目标对象生成代理对象 */
    public T getProxyInstance() {
        // 传入 classLoader、对象的接口和代理对象的方法调用即可
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                (proxy, method, args) -> {
                    System.out.println("Before advice");
                    Object returnValue;
                    try {
                        // 执行目标对象方法
                        returnValue = method.invoke(target, args);
                        System.out.println("After returning advice");
                        return returnValue;
                    } catch (Exception e) {
                        System.out.println("After throwing advice");
                        throw e;
                    } finally {
                        System.out.println("Finally advice");
                    }
                });
    }
}

/** 测试效果 */
public class Main {
    public static void main(String[] args) {
        IUserDao target = new UserDaoImpl();
        // 输出原对象信息
        System.out.println(String.format("origin class: [%s]", target.getClass()));
        IUserDao proxy = new ProxyFactory<>(target).getProxyInstance();
        // 输出代理对象信息
        System.out.println(String.format("proxy class: [%s]", proxy.getClass()));
        // 执行代理方法
        proxy.save();
    }
}

输出
// 实际的对象
origin class: [class me.yuanzx.demo.proxy.jdk.UserDaoImpl]
// 包装出的代理对象
proxy class: [class com.sun.proxy.$Proxy0]
Before advice
实际执行逻辑
After returning advice
Finally advice

3 CGLIB

由于 Java 动态代理的必须要实现接口才行,那么对于没有实现接口的对象怎么实现动态代理呢,这就可以使用 CGLIB,它是通过继承原类实现子类,然后将代理逻辑放到子类里面来实现的。

下面是一个例子

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/** 定义一个接口 */
public interface IUserDao {
    void save();
}

/** 实现一个实现类 */
public class UserDaoImpl implements IUserDao {
    @Override
    public void save() {
        System.out.println("实际执行逻辑");
    }
}

/** 动态代理类实现工厂 */
public class ProxyFactory <T> implements MethodInterceptor{

    /** 维护一个目标对象 */
    private T target;

    public ProxyFactory(T target) {
        this.target = target;
    }

    /** 为目标对象生成代理对象 */
    public T getProxyInstance() {
        // CGLIB 工具类
        Enhancer en = new Enhancer();
        // 设置父类
        en.setSuperclass(target.getClass());
        // 设置回调函数
        en.setCallback(this);
        // 创建子类对象代理
        return (T) en.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Before advice");
        Object returnValue;
        try {
            // 执行目标对象方法
            returnValue = method.invoke(target, args);
            System.out.println("After returning advice");
            return returnValue;
        } catch (Exception e) {
            System.out.println("After throwing advice");
            throw e;
        } finally {
            System.out.println("Finally advice");
        }
    }
}

/** 测试效果 */
public class Main {
    public static void main(String[] args) {
        UserDaoImpl target = new UserDaoImpl();
        // 输出原对象信息
        System.out.println(String.format("origin class: [%s]", target.getClass()));
        UserDaoImpl proxy = new ProxyFactory<>(target).getProxyInstance();
        // 输出代理对象信息
        System.out.println(String.format("proxy class: [%s]", proxy.getClass()));
        // 执行代理方法
        proxy.save();
    }
}

输出
// 实际的对象
origin class: [class me.yuanzx.demo.proxy.jdk.UserDaoImpl]
// 包装出的代理对象
proxy class: [class me.yuanzx.demo.proxy.jdk.UserDaoImpl$$EnhancerByCGLIB$$df9722d4]
Before advice
实际执行逻辑
After returning advice
Finally advice