Java动态代理
来源:互联网 发布:北京值得去的地方知乎 编辑:程序博客网 时间:2024/06/18 11:02
代理模式
Java动态代理
动态代理实现
代理是一种设计模式。在一些情况下,一个对象并不能或者并不希望被其他某些调用,代理就可以在这其中起到中介的作用。
这样既可以使用真实对象的方法,又可以保护目标对象,还可以在真实方法调用的前后进行一些操作。
常见的代理模式实现方式如下:
定义一个接口:
public interface Subject { String doSth(String name); }
实现接口:
public class RealSubject implements Subject{ public String doSth(String name) { return String.format("I'm %s, i am doing Real thing now...",new String[]{name}); } }
如果有这样的情况,我们并不想让测试类直接调用RealSubject的doSth方法。
实现接口,创建一个代理的类,让代理类来调用RealSubject对象的方法 :
public class ProxySubject implements Subject{ private Subject realSubject; public ProxySubject(Subject realSubject) {this.realSubject = realSubject ;} public String doSth(String name) { System.out.println("Proxy start -----"); System.out.println(realSubject.doSth(name)); // 此处执行真实对象的request方法 System.out.println("Proxy end -----"); return "OK"; } }
测试:
public class Test { public static void main(String[] args) { RealSubject realSubject = new RealSubject(); Subject subject = new ProxySubject(realSubject); subject.doSth("Irving"); } }
返回的结果:
Proxy start —–
I’m Irving, i am doing Real thing now…
Proxy end —–
上面实现了一个简单的代理模式,被代理对象的类(RealSubject)和代理类(ProxySubject)都需要实现同一个接口,这会导致
1. 增加维护的复杂度;将来修改接口的时候要改动两个实现,
2. 增加代码量:而且ProxySubject在这里只做了一个“壳”的作用,特意给它写个类实在有点不划算。
此时的代理方式,在程序运行之前就已经确定了谁代理谁。然后按照固定的方式将被代理的对象传入代理类,然后再调用代理类中的方法。
这是静态代理方式。
JDK提供了一种“动态代理”方式:
动态代理类的源码是在程序运行期间由JVM根据反射等动态机制生成的,所以不存在代理类的字节码文件,代理类和被代理的类是在运行期间确定的代理关系。
接下来看看如何使用动态代理的方式生成上面的接口实现RealSubject的代理。
先实现一个处理器,实现InvocationHandler,invoke方法定义了如何处理方法调用时的逻辑,简单处理下:
public class DynamicProxy implements InvocationHandler{ private Object object; public DynamicProxy(Object obj){ object = obj; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Dynamic Proxy start -----"); System.out.println(method.invoke(object, args)); System.out.println("Dynamic Proxy end -----"); return "OK"; } }
调用类实现:
public class TestDynamic { public static void main(String[] args) { Subject realSubject = new RealSubject(); InvocationHandler invocationHandler = new DynamicProxy(realSubject); Class cls = realSubject.getClass(); Subject subject = (Subject)Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),invocationHandler); subject.doSth("IRVING"); } }
从DEBUG说起,可以DEBUG看看生成的Subject subject是什么类型的:
$Proxy0类型的,这明显不是我们自定义的类型。
内部类的定义有规范是 A $ B 的格式,但是这里是以$开头的。感觉应该是标记说明是运行时生成的类对象。观察发现这个对象可以转化成Subject对象,说明这个类可能是实现了这个接口(也可能继承了这个接口的实现类)。
这个对象是如何生成的?
Proxy.newProxyInstance方法传入了三个参数:
加载被代理类的ClassLoader、被代理类型的接口列表、自定义的InvocationHandler实现。
该方法中,有这样一句:
Class<?> cl = getProxyClass0(loader, interfaces);
核心的,这个方法有如下代码:
String proxyName = proxyPkg + proxyClassNamePrefix + num; /* * Verify that the class loader hasn't already * defined a class with the chosen name. */ /* * Generate the specified proxy class. */ byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces); try { proxyClass = defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) {
其中的proxyClassNamePrefix 就是:
/** prefix for all proxy class names */ private final static String proxyClassNamePrefix = "$Proxy";
所以我们的代理类命名为:$Proxy加上一个数字。
byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces);
这句生成了代理类的字节数组,并且结合后面一句,从内存中加载出来创建了代理类。
再简要看看ProxyGenerator的generateProxyClass方法:
public static byte[] generateProxyClass(final String var0, Class[] var1) { ProxyGenerator var2 = new ProxyGenerator(var0, var1); final byte[] var3 = var2.generateClassFile(); if(saveGeneratedFiles) { AccessController.doPrivileged(new PrivilegedAction() { public Void run() { try { FileOutputStream var1 = new FileOutputStream(ProxyGenerator.dotToSlash(var0) + ".class"); var1.write(var3); var1.close(); return null; } catch (IOException var2) { throw new InternalError("I/O exception saving generated file: " + var2); } } }); } return var3; }
除了返回class的字节数组,甚至还发现,如果saveGeneratedFiles参数为true的时候,还能把该class保存到磁盘。
稍微修改下main方法:
public class TestDynamic { public static void main(String[] args) { Subject realSubject = new RealSubject(); InvocationHandler invocationHandler = new DynamicProxy(realSubject); Class cls = realSubject.getClass(); byte[] data = ProxyGenerator.generateProxyClass("$myProxy0", cls.getInterfaces()); FileOutputStream out = null; try { out = new FileOutputStream("E:\\$myProxy0.class"); out.write(data); out.flush(); } catch (Exception e) { e.printStackTrace(); } finally { try { out.close(); } catch (IOException ex) { ex.printStackTrace(); } } } }
用反编译工具查看class的内容:
import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.lang.reflect.UndeclaredThrowableException;public final class $myProxy0 extends Proxy implements Subject{ private static Method m1; private static Method m0; private static Method m3; private static Method m2; public $myProxy0(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 (RuntimeException localRuntimeException) { throw localRuntimeException; } catch (Throwable localThrowable) { } throw new UndeclaredThrowableException(localThrowable); } public final int hashCode() throws { 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 doSth(String paramString) throws { try { return (String)this.h.invoke(this, m3, new Object[] { paramString }); } catch (RuntimeException localRuntimeException) { throw localRuntimeException; } catch (Throwable localThrowable) { } throw new UndeclaredThrowableException(localThrowable); } public final String toString() throws { try { return (String)this.h.invoke(this, m2, null); } catch (RuntimeException localRuntimeException) { throw localRuntimeException; } 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("Subject").getMethod("doSth", new Class[] { Class.forName("java.lang.String") }); 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()); }}
$myProxy0类继承自Proxy并且实现了Subject接口。
除了重写了hashCode和equals方法之外,它也有一个doSth方法,这和我们之前静态代理模式的代理是一个方式,并且doSth方法触发了InvocationHandler对象h的invoke方法。也就是我们自己实现的Handler。
即,调用代理的doSth方法,也就是调用了InvocationHandler的invoke方法。
return (String)this.h.invoke(this, m3, new Object[] { paramString });
- Java 代理,动态代理
- [Java] Java 动态代理
- java代理及动态代理
- java代理模式--动态代理
- Java静态代理、动态代理
- Java 代理之 动态代理
- Java 代理与动态代理
- java静态代理,动态代理
- 代理模式&java动态代理
- Java代理与动态代理
- Java静态代理动态代理
- JAVA代理模式--动态代理
- java 代理和动态代理
- JAVA动态代理 代理模式
- Java动态代理--jdk代理
- Java动态代理--cglib代理
- Java 代理与动态代理
- java代理模式-动态代理
- 我的java学习之路-开发入门常见问题
- 提高浏览体验的五十个最佳FireFox扩展插件
- CQOI2017疯狂爆零记
- 二分查找终极版
- mongodb 中date 类型的处理:ISODate
- Java动态代理
- PHP之Zip扩展,解压缩文件,ZipArchive类
- 切入效果实现
- 利用python将pdf输出为txt
- ajax异步上传文件
- android 热更新框架
- poj 2750 Potted Flower 线段树区间合并加dp
- 运维学习8
- UEFI模式下安装win7