java动态代理模式Proxy之JDK动态代理机制
2016-09-12 22:09
721 查看
JDK动态代理是利用接口,在JVM运行阶段动态生成Class,没错,它是在运行阶段生成的,是和字节码相关的一种操作。
JDK动态代理可以提供对代理对象的访问,可以在对象接口方法的前后处理一些逻辑,使被代理的对象的关注于自身的功能逻辑。JDK动态代理会实现它所表示的实际对象的接口,因此实现接口是最基本的需要。代理对象隐藏了实际对象,因此用户不知道是同代理做交互还是同对象本身做交互。
JDK动态代理首先要有一个动态类,该类得实现接口InvocationHandler。由于JDK代理是基于接口的,所以代理的对象需要实现接口,然后通过Proxy.newProxyInstance方法为目标对象生成代理对象。
代码示例如下:
入口main如下
输出如下:
从输出结果和代码可以看出,Proxy.newProxyInstance生成的代理对象实现了Hello接口,同时,该对象的class是一个com.my.servlet.Proxy0类型的。很奇特吧,我们根本没有定义Proxy0这个class。咦,可能有人会疑惑,是不是jdk库里面有个$Proxy0的实现了Hello接口呢。这是不可能的,jdk库哪有这么神,能未卜先知,猜出你定义的是什么接口。那么这过程是如何实现的呢,下面来反编译进去看一下newProxyInstance方法。
下面是反编译后,newProxyInstance方法的实现,我省略了部分代码,删除了安全验证,异常抛出等其它代码,只留下了主要实现部分
为了更好的认清里面的内容,我把主要实现部分从Proxy移除了出来,写成了方法,便于跟踪。
方法如下
main方法将Proxy.newInstance实现替换成自己的newProxyInstance,替换如下
输出当然一样和刚才一样为
好了,下面要咱们看看这几步的内容
首先,我们在main函数里只执行这几行代码。来看看方法里的第一行到底做了什么
好,执行完后,发现在工作目录底下多了个$Proxy0.class文件
现在,我们来对它进行反编译,得到如下的java文件
有点长,不管它,还是直接上代码,才比较清楚
看到这段代码,发现了吧,该class继承了Proxy,实现了Hello。
里面的say方法如下
h是继承自Proxy的属性
在构造函数中被初始化
这个invocationHandler也就是我们传进去的自己实现的DynamicProxy实例,method是受代理的对象的方法。整个情况瞬间一目了然,JDK动态代理的基本原理过程也就差不多了。一些实现细节方面,就不多说了。
JDK动态代理可以提供对代理对象的访问,可以在对象接口方法的前后处理一些逻辑,使被代理的对象的关注于自身的功能逻辑。JDK动态代理会实现它所表示的实际对象的接口,因此实现接口是最基本的需要。代理对象隐藏了实际对象,因此用户不知道是同代理做交互还是同对象本身做交互。
JDK动态代理首先要有一个动态类,该类得实现接口InvocationHandler。由于JDK代理是基于接口的,所以代理的对象需要实现接口,然后通过Proxy.newProxyInstance方法为目标对象生成代理对象。
代码示例如下:
/** * 对象实现的接口 */ interface Hello { public void say(); }
/** * 接口的实现 */ class HelloImpl implements Hello { public void say() { System.out.println("say"); } }
/** * 代理类的实现 实现了InvocationHandler */ class DynamicProxy implements InvocationHandler { private Object targetObject; public DynamicProxy(Object targetObject) { this.targetObject = targetObject; } public void before() { System.out.println("before-----"); } public void after() { System.out.println("after------"); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before(); method.invoke(targetObject, args); after(); return null; } }
入口main如下
public static void main(String[] args) throws Exception { Hello helloTarget = new HelloImpl(); DynamicProxy dynamicProxy = new DynamicProxy(helloTarget); /* * Proxy.newProxyInstance(ClassLoader classLoader, Class<?>[] interface, InvocationHandler invocationHandler) * 有三个参数 * 第一个为classLoader,这里使用HelloImpl的类加载器 * 第二个为受代理的对象实现的接口,在这里也就是Hello * 第三个为InvocationHandler接口的实现对象,在这里也就是dynamicProxy * 该方法返回一个jvm动态生成的一个代理对象,该对象实现了Hello接口,该对象的class是动态生成的 */ Hello hello = (Hello)Proxy.newProxyInstance(helloTarget.getClass().getClassLoader(), helloTarget.getClass().getInterfaces(), dynamicProxy); hello.say(); System.out.println(hello.getClass().getName()); }
输出如下:
before----- say after------ com.my.servlet.$Proxy0
从输出结果和代码可以看出,Proxy.newProxyInstance生成的代理对象实现了Hello接口,同时,该对象的class是一个com.my.servlet.Proxy0类型的。很奇特吧,我们根本没有定义Proxy0这个class。咦,可能有人会疑惑,是不是jdk库里面有个$Proxy0的实现了Hello接口呢。这是不可能的,jdk库哪有这么神,能未卜先知,猜出你定义的是什么接口。那么这过程是如何实现的呢,下面来反编译进去看一下newProxyInstance方法。
下面是反编译后,newProxyInstance方法的实现,我省略了部分代码,删除了安全验证,异常抛出等其它代码,只留下了主要实现部分
public static Object newProxyInstance(ClassLoader paramClassLoader, Class<?>[] paramArrayOfClass, InvocationHandler paramInvocationHandler) throws IllegalArgumentException { //clone paramArrayOfClass Class[] arrayOfClass = (Class[]) paramArrayOfClass.clone(); //获取我们给的接口来生成代理class,这里是jvm生成字节码的地方 //可能是由于jdk我用的是1.8,反编译器版本没跟上 //反编译出来的部分变量是三个问号 //所以不进去看内部代码了 //有兴趣的可以进ProxyClassFactory查看Apply方法 //ProxyClassFactory是java.lang.reflect.Proxy的一个内部私有类 Class localClass = getProxyClass0(paramClassLoader, arrayOfClass); //利用上面生成的代理class来对传入的paramInvocationHandler获取构造器 Constructor localConstructor = localClass .getConstructor(constructorParams); //利用构造器和传入的InvocationHandler实现对象,生成最终的Proxy return localConstructor .newInstance(new Object[] { paramInvocationHandler }); }
为了更好的认清里面的内容,我把主要实现部分从Proxy移除了出来,写成了方法,便于跟踪。
方法如下
public static Object newProxyInstance(ClassLoader paramClassLoader, Class<?>[] paramArrayOfClass, InvocationHandler paramInvocationHandler) throws Exception { //里面的内容是经过替换后,实现的主干。 //其功能与上面的部分一致,实现主要是放在这里 //当然了,剪去了缓存异常处理等等一系列代码,才看上去这么一点 Class localClass = Proxy.getProxyClass(paramClassLoader, paramArrayOfClass); Constructor localConstructor = localClass .getConstructor(new Class[]{ InvocationHandler.class }); return localConstructor .newInstance(new Object[] { paramInvocationHandler }); }
main方法将Proxy.newInstance实现替换成自己的newProxyInstance,替换如下
Hello hello = (Hello)newProxyInstance(helloTarget.getClass() .getClassLoader(), helloTarget.getClass().getInterfaces(), dynamicProxy);
输出当然一样和刚才一样为
before----- say after------`这里写代码片` com.my.servlet.$Proxy0
好了,下面要咱们看看这几步的内容
首先,我们在main函数里只执行这几行代码。来看看方法里的第一行到底做了什么
public static void main(String[] args) throws Exception { //这一行设置了后,会生成下面的代理的class文件,否则不生成 System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); Hello helloTarget = new HelloImpl(); //第一行的代码 Proxy.getProxyClass(helloTarget.getClass().getClassLoader(), helloTarget.getClass().getInterfaces()); }
好,执行完后,发现在工作目录底下多了个$Proxy0.class文件
现在,我们来对它进行反编译,得到如下的java文件
有点长,不管它,还是直接上代码,才比较清楚
final class $Proxy0 extends Proxy implements Hello { private static Method m1; private static Method m2; private static Method m3; private static Method m0; public $Proxy0(InvocationHandler paramInvocationHandler) { super(paramInvocationHandler); } 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.my.servlet.Hello").getMethod("say", new Class[0]); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); } catch (NoSuchMethodException localNoSuchMethodException) { throw new NoSuchMethodError(localNoSuchMethodException.getMessage()); } catch (ClassNotFoundException localClassNotFoundException) { throw new NoClassDefFoundError( localClassNotFoundException.getMessage()); } } public final void say() { try { //调用我们实现的InvocationHandler里的invoke方法 this.h.invoke(this, m3, null); return; } catch (Error | RuntimeException localError) { throw localError; } 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 (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 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); } } }
看到这段代码,发现了吧,该class继承了Proxy,实现了Hello。
里面的say方法如下
public final void say() { try { //调用我们实现的InvocationHandler里的invoke方法 this.h.invoke(this, m3, null); return; } catch (Error | RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } }
h是继承自Proxy的属性
protected InvocationHandler h;
在构造函数中被初始化
protected Proxy(InvocationHandler paramInvocationHandler) { Objects.req ab57 uireNonNull(paramInvocationHandler); this.h = paramInvocationHandler; }
这个invocationHandler也就是我们传进去的自己实现的DynamicProxy实例,method是受代理的对象的方法。整个情况瞬间一目了然,JDK动态代理的基本原理过程也就差不多了。一些实现细节方面,就不多说了。
相关文章推荐
- 如何使用Proxy模式及Java内建的动态代理机制
- 如何使用Proxy模式及Java内建的动态代理机制
- 如何使用Proxy模式及Java内建的动态代理机制
- 如何使用Proxy模式及Java内建的动态代理机制 推荐
- Proxy模式及Java内建的动态代理机制
- 如何使用Proxy模式及Java内建的动态代理机制
- 如何使用Proxy模式及Java内建的动态代理机制
- 关于java中jdk中接口动态代理模式Proxy的剖析
- java动态代理Proxy 内部机制
- 代理设计模式之(静态代理+Java自身提供的动态代理机制)
- 结构型模式之代理模式(Proxy 与 JDK动态代理)
- 代理模式和java动态代理的机制(一)InvocationHandler
- Java动态代理机制——JDK
- Java动态代理模式(Proxy)实例
- Java设计模式Proxy之动态代理
- [java] JDK 的动态代理机制
- Java设计模式Proxy之动态代理
- java设计模式(七)代理模式和java动态代理机制
- Java程序员从笨鸟到菜鸟之(三十九)大话设计模式(七)代理模式和java动态代理机制
- Java设计模式-----Proxy模式(动态代理)