0%

Java 动态代理(二):Java SDK 动态代理

1. 静态代理和动态代理的区别

  • 在静态代理中,代理类是直接定义在代码中的
  • 在动态代理中,代理类是动态生成

2. 写一个使用 Java SDK 实现动态代理的 Demo

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
public class SimpleJDKDynamicProxyDemo {
static interface IService {
public void sayHello();
}
static class RealService implements IService {
@Override
public void sayHello() {
System.out.println("hello");
}
}
static class SimpleInvocationHandler implements InvocationHandler {
private Object realObj;
public SimpleInvocationHandler(Object realObj) {
this.realObj = realObj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //表示正在被调用的方法
System.out.println("entering " + method.getName());
//注意,不能这样调用:Object result = method.invoke(proxy, args); 否则会造成死循环
Object result = method.invoke(realObj, args);
System.out.println("leaving " + method.getName());
return result;
}
}
public static void main(String[] args) {
IService realService = new ReadService();
IService proxyService = (IService) Proxy.newProxyInstance(IService.class.getClassLoader(), new Class<?>[] { IService.class }, new SimpleInvocationHandler(realService));
proxyService.sayHello();
}
}

3. 接上题,解释一下 java.lang.reflect 包中的 Proxy 类的 newProxyInstance() 方法

  • 该方法声明为:public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
  • 参数 loader 表示类加载器
  • 参数 interfaces 表示代理类要实现的接口列表,是一个数组,元素的类型只能是接口,不能是普通的类
  • 参数 h 的类型为 InvocationHandler,它是一个接口,也定义在 java.lang.reflect 包中,它只定义了一个方法 invoke(),对代理接口所有方法的调用都会转给该方法

4. Proxy.newProxyInstance() 的基本原理

  • 上上题中创建 proxyService 的代码可以用如下代码代替

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //通过 Proxy.getProxyClass 创建代理类定义,类定义会被缓存
    Class<?> proxyCls = Proxy.getProxyClass(IService.class.getClassLoader(), new Class<?>[] { IService.class });

    //获取代理类的构造方法,构造方法有一个 InvocationHandler 类型的参数
    Constructor<?> ctor = proxyCls.getConstructor(new Class<?>[] { InvocationHandler.class});

    //创建 InvocationHandler 对象
    InvocationHandler handler = new SimpleInvocationHandler(realService);

    //创建代理类对象
    IService proxyService = (IService) ctor.newInstance(handler);
  • Proxy.getProxyClass() 需要两个参数:一个是 ClassLoader,一个是接口数组。它会动态生成一个类,类名以 $Proxy 开头,后面跟一个数字$Proxy 的父类是 Proxy

  • 动态生成的 $Proxy 与被代理的对象没有关系,与 InvocationHandler 的具体实现也没有关系,而主要与接口数组有关。给定这个接口数组,它动态创建每个接口的实现代码,实现就是转发给 InvocationHandler,与被代理对象的关系以及对它的调用由 InvocationHandler 的实现管理

  • 如果想知道动态生成的类 $Proxy0 的定义,对于 Oracle 的 JVM,可以配置 java 的一个属性得到。比如:java -Dsun.misc.ProxyGenerator.saveGeneratedFiles=true shuo.laoma.dynamic.c86.SimpleJDKDynamicProxyDemo。以上命令会把动态生成的代理类 $Proxy0 保存到文件 $Proxy.class 中,通过一些反编译工具比如 JD-GUI(http://jd.benow.ca/) 就可以得到源码

5. 相比静态代理,动态代理看起来麻烦了很多,那动态代理的优点是

  • 使用动态代理,可以编写通用的代理逻辑
  • 用于各种类型的被代理对象,而不需要为每个被代理的类型都创建一个静态代理类

6. 写一个通用的动态代理类 Demo

  • 代码

    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
    public class GeneralProxyDemo {
    static interface IServiceA {
    public void sayHello();
    }
    static class ServiceAImpl implements IServiceA {
    @Override
    public void sayHello() {
    System.out.println("hello");
    }
    }
    static interface IServiceB {
    public void fly();
    }
    static class ServiceBImpl implements IServiceB {
    @Override
    public void fly() {
    System.out.println("flying");
    }
    }
    static class SimpleInvocationHandler implements InvocationHandler {
    private Object realObj;
    public SimpleInvocationHandler(Object realObj) {
    this.realObj = realObj;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println("entering " + realObj.getClass().getSimpleName() + ": :" + method.getName());
    Object result = method.invoke(realObj, args);
    System.out.println("leaving " + realObj.getClass().getSimpleName() + ": :" + method.getName());
    return result;
    }
    }
    private static <T> T getProxy(Class<T> intf, T realObj) {
    return (T) Proxy.newProxyInstance(intf.getClassLoader(), new Class<?>[] { intf }, new SimpleInvocationHandler(realObj));
    }
    public static void main(String[] args) throws Exception {
    IServiceA a = new ServiceAImpl();
    IServiceA aProxy = getProxy(IServiceA.class, a);
    aProxy.sayHello();
    IServiceB b = new ServiceBImpl();
    IServiceB bProxy = getProxy(IServiceB.class, b);
    bProxy.fly();
    }
    }
  • 输出

    1
    2
    3
    4
    5
    6
    entering ServiceAImpl : : sayHello
    hello
    leaving ServiceAImpl : : sayHello
    entering ServiceBImpl : : fly
    flying
    leaving ServiceBImpl : : fly
-------------------- 本文结束感谢您的阅读 --------------------