目标

通过代码示例了解动态代理语法

示例代码

 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
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Demo {

    interface MyMath1 {
        public Integer sum(Integer a, Integer b);
    }

    static class MyMathImpl implements MyMath1 {
        @Override
        public Integer sum(Integer a, Integer b) {
            return a + b;
        }
    }

    public static void main(String[] args) {
        MyMath1 tg = new MyMathImpl();
        // 创建对象代理
        MyMath1 math = (MyMath1) Proxy.newProxyInstance(tg.getClass().getClassLoader(), tg.getClass().getInterfaces(), new InvocationHandler() {
            MyMath1 target = tg;

            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                long startTime = System.nanoTime();
                // 代理对象执行方法
                Object result = method.invoke(tg, args);
                long estimatedTime = System.nanoTime() - startTime;
                System.out.println("方法耗时-" + estimatedTime);

                // 问: 形参proxy是干嘛的?
                // 注: 此时有两个MyMath1对象(tg, math),以及一个this关键字
                // this == InvocationHandler对象, proxy == math对象
                return result;
            }
        });
        // 调用被代理后的方法
        System.out.println(math.sum(1, 2));
    }
}
动态代理分jdk版,和cglib版
此示例代码为 jdk版
代码通过为tg对象创建代理,实现了统计方法执行时间的功能
jdk版-动态代理 利用反射机制生成一个实现代理接口的匿名类。 
math对象本就继承了Proxy,java不能多重继承,只能用接口,因此tg对象必须实现过接口。
cglib版-动态代理 要求tg必须实现接口,但要求tg不能为final-class

动态代理-场景

有动态代理的地方肯定有反射,因为其建立在反射之上

  • orm框架的接口注入
  • aop(注解@Transaction, @Cacheable)
    • 日志打印
    • 缓存
    • 事务控制
    • 。。。
  • 远程调用 (反射+ 动态代理+ 序列化== 调用dubbo的rpc服务调用)