1. 静态代理和动态代理的区别
- 在静态代理中,代理类是直接定义在代码中的
- 在动态代理中,代理类是动态生成的
2. 写一个使用 Java SDK 实现动态代理的 Demo
1 | public class SimpleJDKDynamicProxyDemo { |
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
44public class GeneralProxyDemo {
static interface IServiceA {
public void sayHello();
}
static class ServiceAImpl implements IServiceA {
public void sayHello() {
System.out.println("hello");
}
}
static interface IServiceB {
public void fly();
}
static class ServiceBImpl implements IServiceB {
public void fly() {
System.out.println("flying");
}
}
static class SimpleInvocationHandler implements InvocationHandler {
private Object realObj;
public SimpleInvocationHandler(Object realObj) {
this.realObj = realObj;
}
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
6entering ServiceAImpl : : sayHello
hello
leaving ServiceAImpl : : sayHello
entering ServiceBImpl : : fly
flying
leaving ServiceBImpl : : fly