Java JDK动态代理
Posted zeenzhou
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java JDK动态代理相关的知识,希望对你有一定的参考价值。
jdk 动态代理的主要三个部分
1. Proxy 类.
2. ClassLoader
3.InvocationHandler
java中动态代理主要有JDK和CGLIB两种方式。
区别主要是jdk是代理接口,而cglib是代理类。
jdk的动态代理调用了Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法。
通过该方法生成字节码,动态的创建了一个代理类,interfaces参数是该动态类所继承的所有接口,而继承InvocationHandler 接口的类则是实现在调用代理接口方法前后的具体逻辑,下边是具体的实现:
public class Test static interface Subject void sayHi(); void sayHello(); static class SubjectImpl implements Subject @Override public void sayHi() System.out.println("hi"); @Override public void sayHello() System.out.println("hello"); static class ProxyInvocationHandler implements InvocationHandler private Subject target; public ProxyInvocationHandler(Subject target) this.target=target; @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable System.out.print("say:"); return method.invoke(target, args); public static void main(String[] args) Subject subject=new SubjectImpl(); Subject subjectProxy=(Subject) Proxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), new ProxyInvocationHandler(subject)); subjectProxy.sayHi(); subjectProxy.sayHello();
/** * * JDK动态代理类 * * */ public class JDKProxy implements InvocationHandler private Object targetObject;//需要代理的目标对象 public Object newProxy(Object targetObject) //将目标对象传入进行代理 this.targetObject = targetObject; return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);//返回代理对象 public Object invoke(Object proxy, Method method, Object[] args)//invoke方法 throws Throwable before(); Object ret = null; // 设置方法的返回值 ret = method.invoke(targetObject, args); //invoke调用需要代理的方法 after(); return ret; private void before() //方法执行前 System.out.println("方法执行前 !"); private void after() //方法执行后 System.out.println("方法执行后");
newProxyInstance方法执行了以下几种操作。
1.生成一个实现了参数interfaces里所有接口且继承了Proxy的代理类的字节码,然后用参数里的classLoader加载这个代理类。
2.使用代理类父类的构造函数 Proxy(InvocationHandler h)来创造一个代理类的实例,将我们自定义的InvocationHandler的子类传入。
3.返回这个代理类实例。
在main方法中加入System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true"),这样就会把生成的代理类Class文件保存在本地磁盘上,然后再反编译可以得到代理类的源码:
public final class $Proxy0 extends Proxy implements Test.Subject private static Method m4; private static Method m1; private static Method m3; private static Method m0; private static Method m2; static try m4 = Class.forName("Test$Subject").getMethod("sayHello", new Class[0]); m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] Class.forName("java.lang.Object") ); m3 = Class.forName("Test$Subject").getMethod("sayHi", 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 (Exception e) throw new RuntimeException(e); public $Proxy0(InvocationHandler paramInvocationHandler) super(paramInvocationHandler); public final void sayHello() try this.h.invoke(this, m4, null); return; catch (RuntimeException localRuntimeException) throw localRuntimeException; catch (Throwable localThrowable) throw new UndeclaredThrowableException(localThrowable); public final boolean equals(Object paramObject) try return ((Boolean)this.h.invoke(this, m1, new Object[] paramObject )).booleanValue(); catch (RuntimeException localRuntimeException) throw localRuntimeException; catch (Throwable localThrowable) throw new UndeclaredThrowableException(localThrowable); public final void sayHi() try this.h.invoke(this, m3, null); return; catch (RuntimeException localRuntimeException) throw localRuntimeException; catch (Throwable localThrowable) throw new UndeclaredThrowableException(localThrowable); public final int hashCode() try return ((Integer)this.h.invoke(this, m0, null)).intValue(); catch (RuntimeException localRuntimeException) throw localRuntimeException; catch (Throwable localThrowable) throw new UndeclaredThrowableException(localThrowable); public final String toString() try return (String)this.h.invoke(this, m2, null); catch (RuntimeException localRuntimeException) throw localRuntimeException; catch (Throwable localThrowable) throw new UndeclaredThrowableException(localThrowable);
我们可以看到代理类内部实现比较简单,在调用每个代理类每个方法的时候,都用反射去调newProxyInstanceh方法中传来的h的invoke方法(也就是我们自定义的InvocationHandler的子类中重写的invoke方法),用参数传递了代理类实例、接口方法、调用参数列表,这样我们在重写的invoke方法中就可以实现对所有方法的统一包装了。
以上是关于Java JDK动态代理的主要内容,如果未能解决你的问题,请参考以下文章