在上一篇文章设计模式之代理模式里,我们说了JDK动态代理类,不过我相信好多人都有疑惑,包括我,刚开始学的时候都是一脸懵逼,那么到底疑惑在哪里呢?
我的疑惑就是这个InvocationHandler的invoke方法到底是有啥用?我们都没有调用它。newProxyInstance返回的东西到底是啥?等等,这篇文章我们就一起来探讨一下吧。
首先我们先写一个简单的动态代理吧,有例子更好说明。还是买车的例子,哈哈,说明我挺想买车的。我就直接复制上篇文章的。
// Car.java package com.codeliu.dao; public interface Car { // vip客户可以直接买车 public void buyCar(); }
// CarImp1.java package com.codeliu.dao.impl; import com.codeliu.dao.Car; /** * 委托类1 */ public class CarImp1 implements Car { public void buyCar() { System.out.println("我是vip1"); } }
// CarProxy.java package com.codeliu.dao.impl; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 动态代理类 */ public class CarProxy implements InvocationHandler { private Object target; /** * 绑定一个委托对象并获得一个代理类对象 * @param target [description] * @return [description] */ public Object bind(Object target) { this.target = target; // 取得代理对象 return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override //这个方法并不是我们自己去调用 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("调用这个方法前:" + method); // 执行委托类的方法 Object result = method.invoke(target,args); System.out.println("调用这个方法后:" + method); return result; } }
package com.codeliu.test; import com.codeliu.dao.impl.CarImp1; import com.codeliu.dao.impl.CarImp2; import com.codeliu.dao.impl.CarProxy; import com.codeliu.dao.Car; public class TestProxy { public static void main(String[] args) { CarProxy cp = new CarProxy(); // 传入一个实现了该接口的实例就行 Car car = (Car)cp.bind(new CarImp1()); // Car car = (Car)cp.bind(new CarImp2()); car.buyCar(); } }
好了,那么现在我们就来看看Test.java里生成的car对象到底是个什么东a西,是我们的Car接口吗?(我一开始一直理解不通)
我们利用反射可以获取到car对应类的大部分信息,好了,现在我们把Test.java改成如下形式
package com.codeliu.test; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import com.codeliu.dao.Car; import com.codeliu.dao.impl.CarImp1; import com.codeliu.dao.impl.CarProxy; public class Test { public static void main(String[] args) { CarProxy cp = new CarProxy(); // 传入一个实现了该接口的实例就行 Car car = (Car)cp.bind(new CarImp1()); // Car car = (Car)cp.bind(new CarImp2()); car.buyCar(); System.out.println("car是Proxy类的子类吗?" + (car instanceof Proxy)); Class<?> c = car.getClass(); System.out.println(c); System.out.println("car的Class类是:" + c.getName()); Field[] fields = c.getDeclaredFields(); System.out.print("car的Class类中有哪些字段:"); for(Field f:fields) { System.out.print(f.getName() + " "); } System.out.println(); System.out.print("car的Class类中有哪些方法:"); Method[] methods = c.getDeclaredMethods(); for(Method m:methods) { System.out.print(m.getName() + " "); } System.out.println(); System.out.println("car的Class类的父类是:" + c.getSuperclass()); Class<?>[] class1 = c.getInterfaces(); System.out.print("car的Class类实现的接口有:"); for(Class<?> c1:class1) { System.out.println(c1.getName() + " "); } } }
运行一下,输出如下
调用这个方法前:public abstract void com.codeliu.dao.Car.buyCar() 我是vip1 调用这个方法后:public abstract void com.codeliu.dao.Car.buyCar() car是Proxy类的子类吗?true class com.sun.proxy.$Proxy0 car的Class类是:com.sun.proxy.$Proxy0 car的Class类中有哪些字段:m1 m2 m3 m0 car的Class类中有哪些方法:equals toString hashCode buyCar car的Class类的父类是:class java.lang.reflect.Proxy car的Class类实现的接口有:com.codeliu.dao.Car
恩,发现了什么,这个玩意竟然是一个Proxy类的子类,它的名字是$Proxy0,实现了我们自己定义的Car接口,还有四个字段和方法。
既然知道了上面的结果,那么我们就去看看newProxyInstance方法的源码,应该能找到答案了。
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException{ Objects.requireNonNull(h); /* * Look up or generate the designated proxy class. */ Class<?> cl = getProxyClass0(loader, intfs); }
我就截了比较重要的,getProxyClass0方法,它的作用就是生成一个proxy类,好,我们看看这个方法。
private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces) { if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } // If the proxy class defined by the given loader implementing // the given interfaces exists, this will simply return the cached copy; // otherwise, it will create the proxy class via the ProxyClassFactory return proxyClassCache.get(loader, interfaces); }
再去看看这个get方法,emmmmm,代码太多了,尼玛,我也看不太懂,不过经过我查资料,总结如下
newProxyInstance方法调用getProxyClass0生成一个$Proxy0类。
恩没了,现在我们要找答案就得去看看$Proxy0类的源码了。
因为生成的是一个.class文件,所以我们先反编译后,可以看到源码如下
package com.sun.proxy; import com.codeliu.dao.Car; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy0 extends Proxy implements Car { private static Method m1; private static Method m2; private static Method m3; private static Method m0; public $Proxy0(InvocationHandler paramInvocationHandler) { super(paramInvocationHandler); } public final boolean equals(Object paramObject) { try { return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue(); } catch (Error|RuntimeException localError { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final String toString() { try { return (String)this.h.invoke(this, m2, null); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final void buyCar() { try { this.h.invoke(this, m3, null); return; } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final int hashCode() { try { return ((Integer)this.h.invoke(this, m0, null)).intValue(); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); m3 = Class.forName("com.codeliu.dao.Car").getMethod("buyCar", new Class[0]); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); return; } catch (NoSuchMethodException localNoSuchMethodException) { throw new NoSuchMethodError(localNoSuchMethodException.getMessage()); } catch (ClassNotFoundException localClassNotFoundException) { throw new NoClassDefFoundError(localClassNotFoundException.getMessage()); } } }
$Proxy0继承了Proxy类并实现了Car接口,它有一个构造方法,传入了一个InvocationHandler实例并调用了父类的构造方法,然后是四个final方法,其他三个是Object类传过来的,还有一个叫buyCar,这不就是我们在接口中定义的吗?我们看看它怎么写的
public final void buyCar() { try { this.h.invoke(this, m3, null); return; } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } }
恩,首先m3在静态块中,取得Car接口中的buyCar方法,然后是调用invoke方法,666,现在终于解决了文章开头的疑惑,原来在这里调用了,等等,那么这个h又是什么东西,我们看看Proxy的源码
protected InvocationHandler h; protected Proxy(InvocationHandler h) { Objects.requireNonNull(h); this.h = h; }
一个字段和一个带参的构造函数,我们再看看$Proxy0的源码中有这么一段
public $Proxy0(InvocationHandler paramInvocationHandler) { super(paramInvocationHandler); }
好家伙,到这里就真相大白了,虽然我还是不知道这个$Proxy0.class怎么生出来的,但基本也懂了,再总结一下整趟流程。
首先是我们写了一个接口,一个委托类实现了这个接口,然后写一个代理类实现InvocationHandler接口并重写invoke方法,之后调用Proxy的newProxyInstance方法,这个方法调用getProxyClass0方法生成一个动态代理对象,这个对象对应的类是 Proxy0