, 以前一直没觉得,现在发现写博客还是一件蛮有趣的事情, :)
动态代理的实现有两种方式: 一种是jdk的动态代理,实现类必须实现某个接口; 另一种是cglib,使用底层的字节码技术,对实现类没有要求。
首先来看一个简单使用jdk动态代理的例子:
第一步: 定义接口
public interface Animal { public String getName(); }
第二步:具体实现类
public class Dog implements Animal { @Override public String getName() { System.out.println("***pretty dog***"); return "Dog"; } }
第三步:实现代理类,代理类需要实现InvocationHandler接口
public class ProxyTest implements InvocationHandler { private Animal animal; public ProxyTest(Animal animal) { super(); this.animal = animal; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("---before method---"); Object obj = method.invoke(animal, args); System.out.println("---after method---"); return obj; } public static void main(String[] args) { Animal animal = new Dog(); ClassLoader classLoader = animal.getClass().getClassLoader(); Class<?>[] interfaces = animal.getClass().getInterfaces(); InvocationHandler h = new ProxyTest(animal); Animal proxyAnimal = (Animal) Proxy.newProxyInstance(classLoader, interfaces, h); proxyAnimal.getName(); } }
运行上面的代码,输出结果如下:
---before method---
***pretty dog***
---after method---
下面来看下代码的调用过程,在main方法中,调用Proxy.newProxyInstance方法来生成代理对象,code如下:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { if (h == null) { throw new NullPointerException(); } /* * Look up or generate the designated proxy class. */ Class cl = getProxyClass(loader, interfaces); /* * Invoke its constructor with the designated invocation handler. */ try { Constructor cons = cl.getConstructor(constructorParams); return (Object) cons.newInstance(new Object[] { h }); } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); } catch (IllegalAccessException e) { throw new InternalError(e.toString()); } catch (InstantiationException e) { throw new InternalError(e.toString()); } catch (InvocationTargetException e) { throw new InternalError(e.toString()); } }
在newProxyInstance方法中,通过调用getProxyClass方法来获取代理类的class对象,主要代码如下(原方法较长,只是选择了部分关键的code):
public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException { Map cache; /* * 如果已经创建或者正在创建代理对象,则直接返回或者等待创建完成;否则跳出循环 */ synchronized (cache) { do { Object value = cache.get(key); if (value instanceof Reference) { proxyClass = (Class) ((Reference) value).get(); } if (proxyClass != null) { // proxy class already generated: return it return proxyClass; } else if (value == pendingGenerationMarker) { // proxy class being generated: wait for it try { cache.wait(); } catch (InterruptedException e) { /* * The class generation that we are waiting for should * take a small, bounded time, so we can safely ignore * thread interrupts here. */ } continue; } else { /* * No proxy class for this list of interfaces has been * generated or is being generated, so we will go and * generate it now. Mark it as pending generation. */ cache.put(key, pendingGenerationMarker); break; } } while (true); } byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces); try { proxyClass = defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { } return proxyClass; }
ProxyGenerator在rt.jar中,需要先下载源码,我是直接使用eclipse 的反编译工具来看。可以参考链接: http://tangmingjie2009.iteye.com/blog/1916992。
最终生成的代理类经反编译之后如下(下面的文件是直接通过调用byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy1", animal.getClass().getInterfaces()) 生成):
public final class $Proxy1 extends Proxy implements Animal { public $Proxy1(InvocationHandler invocationhandler) { super(invocationhandler); } public final String getName() { try { return (String)super.h.invoke(this, m3, null); } catch(Error _ex) { } catch(Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final boolean equals(Object obj) { try { return ((Boolean)super.h.invoke(this, m1, new Object[] { obj })).booleanValue(); } catch(Error _ex) { } catch(Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final int hashCode() { try { return ((Integer)super.h.invoke(this, m0, null)).intValue(); } catch(Error _ex) { } catch(Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final String toString() { try { return (String)super.h.invoke(this, m2, null); } catch(Error _ex) { } catch(Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } private static Method m3; private static Method m1; private static Method m0; private static Method m2; static { try { m3 = Class.forName("ss.proxy.Animal").getMethod("getName", new Class[0]); m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); } catch(NoSuchMethodException nosuchmethodexception) { throw new NoSuchMethodError(nosuchmethodexception.getMessage()); } catch(ClassNotFoundException classnotfoundexception) { throw new NoClassDefFoundError(classnotfoundexception.getMessage()); } } }
因此当调用ProxyTest中的getName的方法时,会调用$Proxy1对象的getName方法,然后通过super.h.invoke(this, m3, null)调用ProxyTest的invoke方法,其中参数m3为Dog的getName方法。