动态代理的一点理解
程序设计里面有一种设计模式叫做代理模式。“代理”顾名思义,就是你想做一件事,但是不想自己去做,这个时候可以委托别人去帮你办理这件事。
话不多说,下面以Java代码来举例说明。
1 Subject.java
2 package staticproxy.learn;
3
4 interface Subject {
5 public void doSomething();
6 }
1 RealSubject.java
2 package staticproxy.learn;
3
4 class RealSubject implements Subject {
5 public void doSomething() {
6 System.out.println("doSomething()");
7 }
8 }
1 Client.java
2 package staticproxy.learn;
3
4 public class Client {
5 public static void main(String args[]) {
6 Subject real = new RealSubject();
7 real.doSomething();
8 }
9 }
输出结果:
doSomething()
如果我们想计算doSomething()执行的时间是多少,怎么办呢?我们想到最简单的一种方法就是修改doSomething()这个方法,如下:
1 RealSubject.java
2 package staticproxy.learn;
3
4 class RealSubject implements Subject {
5 public void doSomething() {
6 long startTime=System.nanoTime();
7 System.out.println("doSomething()");
8 long endTime=System.nanoTime();
9 System.out.println("程序运行时间: "+(endTime-startTime)+"ns");
10 }
11 }
1 Client.java
2 package staticproxy.learn;
3
4 public class Client {
5 public static void main(String args[]) {
6 Subject real = new RealSubject();
7 real.doSomething();
8 }
9 }
输出结果:
doSomething()
程序运行时间: 141512ns
方法2:
增加一个类叫做ProxySubject.java,让它也实现Subject这个接口,然后实现doSomething()的这个方法,在这个方法里面把计算程序运行时间的代码添加上,如下:
1 ProxySubject.java
2 package staticproxy.learn;
3
4 public class ProxySubject implements Subject {
5
6 private Subject object = new RealSubject();
7
8 @Override
9 public void doSomething() {
10 long startTime=System.nanoTime();
11 object.doSomething();
12 long endTime=System.nanoTime();
13 System.out.println("程序运行时间: "+(endTime-startTime)+"ns");
14 }
15 }
1 Client.java
2 package staticproxy.learn;
3
4 public class Client {
5 public static void main(String args[]) {
6 ProxySubject ps = new ProxySubject();
7 ps.doSomething();
8 }
9 }
输出结果:
doSomething()
程序运行时间: 134980ns
方法2有一个称呼叫做静态代理,所有的操作都委托ProxySubject这个类来完成。
之所以叫做静态代理,是因为代理类是我们手动写代码来完成的。
方法1,2的缺点:如果Subject这个接口里面有很多方法,那么是不是实现类里面也要相应的修改多少个,这样会导致类的急剧膨胀,显然不是最好的方法。
还有没有更好的方法来实现上面的需求呢,当然有,相当于静态代理,动态代理就应运而生了。
话不多说,直接看效果。
1 Subject.java
2 package dynamic.proxy.learn;
3
4 interface Subject {
5 public void doSomething();
6 }
1 RealSubject.java
2 package staticproxy.learn;
3
4 class RealSubject implements Subject {
5 public void doSomething() {
6 System.out.println("doSomething()");
7 }
8 }
一个实现了InvocationHandler接口的实际实现类,这个接口里面只有一个方法invoke()
1 package dynamic.proxy.learn;
2
3 import java.lang.reflect.InvocationHandler;
4 import java.lang.reflect.Method;
5
6 class ProxyHandler implements InvocationHandler {
7 private Object proxied;
8
9 public ProxyHandler(Object proxied) {
10 this.proxied = proxied;
11 }
12
13 @Override
14 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
15 long startTime=System.nanoTime();
16 Object rs = method.invoke(proxied, args);
17 long endTime=System.nanoTime();
18 System.out.println("程序运行时间: "+(endTime-startTime)+"ns");
19 return rs;
20 }
21 }
1 Client.java
2 package dynamic.proxy.learn;
3
4 import java.lang.reflect.Proxy;
5
6 public class Client {
7 public static void main(String args[]) {
8 Subject real = new RealSubject();
9 Subject proxySubject = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(), new Class[] { Subject.class }, new ProxyHandler(real));
10 proxySubject.doSomething();
11 }
12 }
输出结果:
doSomething()
程序运行时间: 311015ns
程序达到了同样的效果,这里估计都有2个疑问。
1,ProxyHandler里面的invoke方法究竟是被谁调用的?
2,Subject proxySubject = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(), new Class[] { Subject.class }, new ProxyHandler(real));
这里的proxySubject对象究竟是怎么样的?
带着这些疑问,先抛出答案,再行分析究竟是怎么回事。
原来程序在执行的时候,会自动生成一个$proxy1.java(实际名字前面有包名,后面有num)的实际代理类,这个类的主要代码如下:
1 package dynamic.proxy.learn;
2
3 import java.lang.reflect.InvocationHandler;
4 import java.lang.reflect.Method;
5 import java.lang.reflect.Proxy;
6 import java.lang.reflect.UndeclaredThrowableException;
7
8 public final class ProxySubject extends Proxy implements Subject {
9
10 private static final long serialVersionUID = 1L;
11 private static Method m1;
12 private static Method m0;
13 private static Method m3;
14 private static Method m2;
15 static {
16 try {
17 m1 = Class.forName("java.lang.Object").getMethod("equals",
18 new Class[] { Class.forName("java.lang.Object") });
19 m0 = Class.forName("java.lang.Object").getMethod("hashCode",
20 new Class[0]);
21 m3 = Class.forName("jdbctest.Subject").getMethod("doSomething",
22 new Class[0]);
23 m2 = Class.forName("java.lang.Object").getMethod("toString",
24 new Class[0]);
25 return;
26 } catch (NoSuchMethodException localNoSuchMethodException) {
27 throw new
28 NoSuchMethodError(localNoSuchMethodException.getMessage());
29 } catch (ClassNotFoundException localClassNotFoundException) {
30 throw new
31 NoClassDefFoundError(localClassNotFoundException.getMessage());
32 }
33 }
34
35 public ProxySubject(InvocationHandler paramInvocationHandler)
36
37 {
38 super(paramInvocationHandler);
39 }
40
41 public final void doSomething()
42
43 {
44 try {
45 this.h.invoke(this, m3, null);
46 return;
47 } catch (Error | RuntimeException localError) {
48 throw localError;
49 } catch (Throwable localThrowable) {
50 throw new UndeclaredThrowableException(localThrowable);
51 }
52 }
53
54 public final boolean equals(Object paramObject)
55
56 {
57 try {
58 return ((Boolean) this.h.invoke(this, m1,
59 new Object[] { paramObject })).booleanValue();
60 } catch (Error | RuntimeException localError) {
61 throw localError;
62 } catch (Throwable localThrowable) {
63 throw new UndeclaredThrowableException(localThrowable);
64 }
65 }
66
67 public final int hashCode()
68
69 {
70 try {
71 return ((Integer) this.h.invoke(this, m0, null)).intValue();
72 } catch (Error | RuntimeException localError) {
73 throw localError;
74 } catch (Throwable localThrowable) {
75 throw new UndeclaredThrowableException(localThrowable);
76 }
77 }
78
79
80
81 public final String toString()
82
83 {
84 try {
85 return (String) this.h.invoke(this, m2, null);
86 } catch (Error | RuntimeException localError) {
87 throw localError;
88 } catch (Throwable localThrowable) {
89 throw new UndeclaredThrowableException(localThrowable);
90 }
91 }
92 }
这个类里面有一个带参数的构造方法,这个参数需要传递实现了接口InvocationHandler的ProxyHandler的实例,然后这个类里面有一个同样的doSomething()方法,在这个方法里面有一句this.h.invoke(this, m3, null);正是这一句代码,ProxyHandler里面的invoke方法才得以调用。
接下来继续分析源码,看它是如何动态实现的。
1 Subject proxySubject = (Subject) Proxy.newProxyInstance(
2 Subject.class.getClassLoader(), new Class[] { Subject.class },
3 new ProxyHandler(real));
Proxy.newProxyInstance的分析
Proxy.newProxyInstance这个方法里面一共有三个参数:
* ClassLoader loader : 指定被代理对象的类加载器
* Class<?>[] interfaces: 指定被代理对象所实现的接口
* InvocationHandler h: 指定需要调用的InvocationHandler对象
1 public static Object newProxyInstance(ClassLoader loader,
2 Class<?>[] interfaces,
3 InvocationHandler h)
4 throws IllegalArgumentException
5 {
6 // h不能为空
7 Objects.requireNonNull(h);
8 // 安全检查
9 final SecurityManager sm = System.getSecurityManager();
10 if (sm != null) {
11 checkProxyAccess(Reflection.getCallerClass(), loader, interfaces);
12 }
13
14 // 主要的代理就是这一句,生成代理类
15 Class<?> cl = getProxyClass0(loader, interfaces);
16 try {
17 if (sm != null) {
18 checkNewProxyPermission(Reflection.getCallerClass(), cl);
19 }
20 // 取得代理类的构造函数(不懂的同学,请学习一下Java的反射)
21 final Constructor<?> cons = cl.getConstructor(constructorParams);
22 final InvocationHandler ih = h;
23 if (!Modifier.isPublic(cl.getModifiers())) {
24 AccessController.doPrivileged(new PrivilegedAction<Void>() {
25 public Void run() {
26 cons.setAccessible(true);
27 return null;
28 }
29 });
30 }
31 // 取得代理类的实例
32 return cons.newInstance(new Object[]{h});
33 } catch (IllegalAccessException|InstantiationException e) {
34 throw new InternalError(e.toString(), e);
35 } catch (InvocationTargetException e) {
36 Throwable t = e.getCause();
37 if (t instanceof RuntimeException) {
38 throw (RuntimeException) t;
39 } else {
40 throw new InternalError(t.toString(), t);
41 }
42 } catch (NoSuchMethodException e) {
43 throw new InternalError(e.toString(), e);
44 }
45 }
getProxyClass0方法的分析
1 /**
2 * Generate a proxy class. Must call the checkProxyAccess method
3 * to perform permission checks before calling this.
4 */
5 private static Class<?> getProxyClass0(ClassLoader loader,
6 Class<?>... interfaces) {
7 // 被代理对象的接口数量不能超过65535个,否则抛出错误
8 if (interfaces.length > 65535) {
9 throw new IllegalArgumentException("interface limit exceeded");
10 }
11
12 // If the proxy class defined by the given loader implementing
13 // the given interfaces exists, this will simply return the cached copy;
14 // otherwise, it will create the proxy class via the ProxyClassFactory
15 // 简单一点就是说,缓存里面存在代理就从里面取,没有就创建一个新的代理对象
16 return proxyClassCache.get(loader, interfaces);
17 }
再看看这个get方法
1 public V get(K key, P parameter) {
2 Objects.requireNonNull(parameter);
3 ...
4 Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
5 ...
6 }
这里的subKeyFactory是实现了BiFunction接口的ProxyClassFactory的一个实例
ProxyClassFactory分析
1 private static final class ProxyClassFactory
2 implements BiFunction<ClassLoader, Class<?>[], Class<?>> {
3 // 代理类名字的前缀
4 private static final String proxyClassNamePrefix = "$Proxy";
5
6 // 计数器
7 private static final AtomicLong nextUniqueNumber = new AtomicLong();
8
9 @Override
10 public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
11
12 String proxyPkg = null;
13 // 非公共接口,代理类的包名与接口的相同
14 for (Class<?> intf : interfaces) {
15 int flags = intf.getModifiers();
16 if (!Modifier.isPublic(flags)) {
17 String name = intf.getName();
18 int n = name.lastIndexOf('.');
19 String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
20 if (proxyPkg == null) {
21 proxyPkg = pkg;
22 } else if (!pkg.equals(proxyPkg)) {
23 throw new IllegalArgumentException(
24 "non-public interfaces from different packages");
25 }
26 }
27 }
28
29 // 对于公共接口的包名,默认为com.sun.proxy
30 if (proxyPkg == null) {
31 proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
32 }
33
34 // 取得计数
35 long num = nextUniqueNumber.getAndIncrement();
36 // 代理类的名字
37 String proxyName = proxyPkg + proxyClassNamePrefix + num;
38
39 // 生成代理类的字节码
40 byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
41 proxyName, interfaces);
42 try {
43 // 根据二进制字节码返回相应的Class实例
44 return defineClass0(loader, proxyName,
45 proxyClassFile, 0, proxyClassFile.length);
46 } catch (ClassFormatError e) {
47 throw new IllegalArgumentException(e.toString());
48 }
49 }
50 }
// 生成代理类的字节码
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces);
这部分代码没有开源,实现的功能就是会生成代理类的*.class文件,并且返回字节码数组。
以上就是动态代理的全部实现过程。