java jdk动态代理原理

来源:互联网 发布:北科大东凌经管知乎 编辑:程序博客网 时间:2024/05/20 05:24

使用示例

package com.basic.proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class TestJdkProxy {public static void main(String[] args) {IPerson p = createJdkDynamicProxy(new Person());p.getPersonNum();Class<?>[] classz = new Class[] {IPerson.class};for (Class<?> clasz : classz) {System.out.println(clasz.getName());}Class<?>[] classi = p.getClass().getInterfaces();for (Class<?> clasi : classi) {System.out.println(clasi.getName());}}private static IPerson createJdkDynamicProxy(final IPerson delegate) {  IPerson jdkProxy = (IPerson) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),  new Class[] {IPerson.class}, new JdkHandler(delegate));          return jdkProxy;      }            private static class JdkHandler implements InvocationHandler {            final Object delegate;            JdkHandler(Object delegate) {              this.delegate = delegate;          }            public Object invoke(Object object, Method method, Object[] objects)                  throws Throwable {              return method.invoke(delegate, objects);          }      }}public interface IPerson {    public int getPersonNum();}public class Person implements IPerson {        @Override    public int getPersonNum() {        System.out.println("Person.getPersonNum");        return 0;    }}

原理解析

1、实现InvocationHandler接口,该接口需要实现invoke方法,在invoke方法内部,基于反射机制调用Method的invoke方法,该方法要求一个被代理类的对象,所以InvocationHandler的实现类必须申明一个被代理类对象的属性必须在构造的时候给其赋值。

2、Proxy.newProxyInstance方法,改方法要求3个参数,一类加载器,二接口类数组,三InvocationHandler的实现类,具体流程如下

1)基于接口产生字节码,然后基于字节码生成代理类的class对象,主要调用过程为

/*                 * Generate the specified proxy class.                 */                byte[] proxyClassFile = ProxyGenerator.generateProxyClass(                    proxyName, interfaces);                try {                    proxyClass = 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());                }
2)在我们的应用程序中,我们也可以使用ProxyGenerator.generateProxyClass()函数来生成字节码文件,然后再反编译为java,这样我们就可以看到Jdk为我们生成的代理类的具体内容了。下面结合代理类进一步分析:

import com.basic.proxy.IPerson;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.lang.reflect.UndeclaredThrowableException;public final class $Proxy11 extends Proxy  implements IPerson{  private static Method m1;  private static Method m0;  private static Method m3;  private static Method m2;  public $Proxy11(InvocationHandler paramInvocationHandler)    throws   {    super(paramInvocationHandler);  }  public final boolean equals(Object paramObject)    throws   {    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 int hashCode()    throws   {    try    {      return ((Integer)this.h.invoke(this, m0, null)).intValue();    }    catch (Error|RuntimeException localError)    {      throw localError;    }    catch (Throwable localThrowable)    {      throw new UndeclaredThrowableException(localThrowable);    }  }  public final int getPersonNum()    throws   {    try    {      return ((Integer)this.h.invoke(this, m3, null)).intValue();    }    catch (Error|RuntimeException localError)    {      throw localError;    }    catch (Throwable localThrowable)    {      throw new UndeclaredThrowableException(localThrowable);    }  }  public final String toString()    throws   {    try    {      return (String)this.h.invoke(this, m2, null);    }    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") });      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);      m3 = Class.forName("com.basic.proxy.IPerson").getMethod("getPersonNum", new Class[0]);      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);      return;    }    catch (NoSuchMethodException localNoSuchMethodException)    {      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());    }    catch (ClassNotFoundException localClassNotFoundException)    {      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());    }  }}
通过上面的代理类代码,可以看出代理类继承了Proxy类,并且实现了IPerson接口和接口定义的方法,方法内部调用了InvocationHandler实现类的Invoke方法。

public final int getPersonNum() {......return ((Integer)this.h.invoke(this, m3, null)).intValue();......}
从上面的语句可以得知,InvocationHandler的具体类的invoke方法的Object对象实际上就是代理类对象,Method方法就是代理类对象调用的方法,它通过static块语句获取,
m3 = Class.forName("com.basic.proxy.IPerson").getMethod("getPersonNum", new Class[0]);

3)基于生成的代理类Class对象,使用构造函数方法生成具体的代理类对象

final Constructor<?> cons = cl.getConstructor(constructorParams);return cons.newInstance(new Object[] {h} );

总结:基于上面的分析,JDK动态代理的原理和代理类调用方法的过程还是比较清楚的。当然了整个过程的重点实际上还是基于接口生成字节码,然后基于字节码生成代理类的Class对象,这两个过程没有具体分析了,感兴趣的可以继续深入里面看看。


0 0