jdk动态代理通过jdk提供的Proxy类和InvocationHandler接口实现动态代理,但是jdk动态代理需要被代理的对象一定要实现了接口,更具体来说,实现的接口中的方法就是你想要代理的方法,在被代理类中不是实现接口中的方法的方法是不会被代理的。
下面来看一下InvocationHandler接口的源码:
public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }下面是Proxy类的部分方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { if (h == null) { throw new NullPointerException(); } final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /* * Look up or generate the designated proxy class. */ Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) { // create proxy instance with doPrivilege as the proxy class may // implement non-public interfaces that requires a special permission return AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { return newInstance(cons, ih); } }); } else { return newInstance(cons, ih); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); } }newProxyInstance方法就用来创建代理类的对象的,可以看到必须要有被代理对象的实现的接口,最重要的是最有一个参数InvocationHandler对象,实际这里我们传入的会是实现了InvocationHandler接口并且包含被代理对象的实例。
下面是我们实现了InvocationHandler接口的类:
public class MyInvocationHandler implements InvocationHandler { // 目标对象 private Object target; /** * 构造方法 * @param target 目标对象 */ public MyInvocationHandler(Object target) { super(); this.target = target; } /** * 执行目标对象的方法 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 在目标对象的方法执行之前简单的打印一下 System.out.println("------------------before------------------"); // 执行目标对象的方法 Object result = method.invoke(target, args); // 在目标对象的方法执行之后简单的打印一下 System.out.println("-------------------after------------------"); return result; } /** * 获取目标对象的代理对象 * @return 代理对象 */ public Object getProxy() { return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this); } }把被代理对象最为构造函数参数传入到MyInvocationHandler类中,主要是为了要在invoke方法中使用,我们现在看invoke方法:
使用java的反射机制通过method.invoke调用被代理对象的method,在invoke方法上下可以加入增强功能,比如可以加上一些日志记录,事务控制功能等等
下面再看我们自定义的getProxy方法,可以获得代理类实例对象,在newProxyInstance方法中出入了this,那么传入的invocationHandler对象是怎样能够生成代理类的呢?
下面来看一下Proxy类的
/** * Generate a proxy class. Must call the checkProxyAccess method * to perform permission checks before calling this. */ 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); }
下面是ProxyClassFactory代理类工场,生成代理类的地方。下面是这个类怎样为代理类拼接名字的:
// prefix for all proxy class names private static final String proxyClassNamePrefix = "$Proxy"; // next number to use for generation of unique proxy class names private static final AtomicLong nextUniqueNumber = new AtomicLong();
/* * Choose a name for the proxy class to generate. */ long num = nextUniqueNumber.getAndIncrement(); String proxyName = proxyPkg + proxyClassNamePrefix + num; /* * Generate the specified proxy class. */ byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces); try { return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { /* * A ClassFormatError here means that (barring bugs in the * proxy class generation code) there was some other * invalid aspect of the arguments supplied to the proxy * class creation (such as virtual machine limitations * exceeded). */ throw new IllegalArgumentException(e.toString()); }里面会使用java1.5之后提供的原子操作类中的AutomicLong,能够通过CAS算法硬件支持来实现++自增原子操作。代理类的名字一般拼接成这样的$Proxy1
通过ProxyGenrator的genrateProxyClass方法生成类文件定义的字符串的byte数组(这里我没有去看方法的源码),然后作为参数传递给defineClass0来在本地硬盘上生成代理类,然后并通过类加载器把类加载到jvm中,并把Class对象返回,这样就得到了代理类的Class对象了。
我们可以直接调用ProxyGenerator的generateProxyClass方法来获取代理类的字节码byte数组,然后写到自己指定的硬盘地址,就能找到代理类的class文件了,然后通过反编译工具查看源码:
// 获取代理类的字节码 byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy11", UserServiceImpl.class.getInterfaces());
下面来看一下一个例子,看看代理类具体时什么样的:
public final class $Proxy11 extends Proxy implements UserService { // 构造方法,参数就是刚才传过来的MyInvocationHandler类的实例 public $Proxy11(InvocationHandler invocationhandler) { super(invocationhandler); } 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 void add() { try { // 实际上就是调用MyInvocationHandler的public Object invoke(Object proxy, Method method, Object[] args)方法,第二个问题就解决了 super.h.invoke(this, m3, null); return; } 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 m1; private static Method m3; private static Method m0; private static Method m2; // 在静态代码块中获取了4个方法:Object中的equals方法、UserService中的add方法、Object中的hashCode方法、Object中toString方法 static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m3 = Class.forName("dynamic.proxy.UserService").getMethod("add", new Class[0]); 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()); } } }
说到底,还是Proxy类中生成代理类的字节码内容是自定义的,这样可以巧妙的生成上面类的定义,可以实现方法相对应,并且在类加载到内存后,在显示使用代理类时初始化,执行静态代码块儿实例化method对象。
根据提供的生成的代理类,类加载器,根据传入的代理类的字节码数组返回代理类的Class对象
private static native Class defineClass0(ClassLoader loader, String name, byte[] b, int off, int len);
简单的分析了一下JDK动态代理类的创建过程,JDK动态代理必须要实现接口,这是一个局限点,当我们需要被代理的对象没有实现接口就无法使用了,那么就需要使用cglib来生成代理类了。后面会介绍一下cglib生成代理类的原理。