读书人

深入研究java中的静态署理和动态代理

发布时间: 2013-09-08 15:21:21 作者: rapoo

深入研究java中的静态代理和动态代理
java编码中经常用到代理,代理分为静态代理和动态代理。一、静态代理:程序运行之前,程序员就要编写proxy,然后进行编译,即在程序运行之前,代理类的字节码文件就已经生成了被代理类的公共父类package staticproxy;public abstract class BaseClass { public abstract void add();}被代理类package staticproxy;public class A extends BaseClass { public void add() { System.out.println("A add !"); }}代理类package staticproxy;public class Proxy { BaseClass baseClass; public void add() { baseClass.add(); } public void setBaseClass(BaseClass baseClass) { this.baseClass = baseClass; } public static void main(String[] args) { BaseClass baseClass = new A(); Proxy proxy = new Proxy(); proxy.setBaseClass(baseClass); proxy.add(); }}二、动态代理:实际的代码在编译期间并没有生成,而是在运行期间运用反射机制动态的生成被代理类接口package jdkproxy;public interface Service { public void add(); public void update();}被代理类Apackage jdkproxy;public class AService implements Service { public void add() { System.out.println("AService add>>>>>>>>>>>>>>>>>>"); } public void update() { System.out.println("AService update>>>>>>>>>>>>>>>"); }}被代理类Bpackage jdkproxy;public class BService implements Service { public void add() { System.out.println("BService add---------------"); } public void update() { System.out.println("BService update---------------"); }}代理类package jdkproxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class MyInvocationHandler implements InvocationHandler { private Object target; MyInvocationHandler() { super(); } 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; } public Object getTarget() { return target; } public void setTarget(Object target) { this.target = target; }}测试类package jdkproxy;import java.lang.reflect.Proxy;public class Test { public static void main(String[] args) { Service aService = new AService(); MyInvocationHandler handler = new MyInvocationHandler(aService); // Proxy为InvocationHandler实现类动态创建一个符合某一接口的代理实例 Service aServiceProxy = (Service) Proxy.newProxyInstance(aService .getClass().getClassLoader(), aService.getClass() .getInterfaces(), handler); //由动态生成的代理对象来aServiceProxy 代理执行程序,其中aServiceProxy 符合Service接口 aServiceProxy.add(); System.out.println(); aServiceProxy.update(); // 以下是对B的代理 // Service bService = new BService(); // MyInvocationHandler handler = new MyInvocationHandler(bService); // Service bServiceProxy = (Service) Proxy.newProxyInstance(bService // .getClass().getClassLoader(), bService.getClass() // .getInterfaces(), handler); // bServiceProxy.add(); // System.out.println(); // bServiceProxy.update(); }}输出结果:before-----------------------------AService add>>>>>>>>>>>>>>>>>>after------------------------------before-----------------------------AService update>>>>>>>>>>>>>>>after------------------------------其中上述标红的语句是产生代理类的关键代码,可以产生一个符合Service接口的代理对象,newProxyInstance这个方法会做这样一件事情,他将把你要代理的全部接口,用一个由代码动态生成的类来实现,该类中所有的接口中的方法都重写为调用InvocationHandler.invoke()方法。下面详细介绍是如何实现代理对象的生成的Proxy的newProxyInstance方法,其中,为了看起来方便,已经将该方法中的异常处理语句删减下下面public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h) throws public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException { if (h == null) { throw new NullPointerException(); } //生成指定的代理类 Class cl = getProxyClass(loader, interfaces); Constructor cons = cl.getConstructor(constructorParams); // 生成代理类的实例,并把MyInvocationHandler的实例传给它的构造方法,代理类对象实际执行都会调用MyInvocationHandler的invoke方法,所以代理类对象中维持一个MyInvocationHandler引用 return (Object) cons.newInstance(new Object[] { h }); } 其中getProxyClass方法返回代理类的实例Proxy的getProxyClass方法public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException{ //前面省略很多缓存、异常处理、判断逻辑代码,为了使程序更加突出 byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces); proxyClass = defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length); proxyClasses.put(proxyClass, null); return proxyClass;}下面看ProxyGenerator的generateProxyClass方法,该方法最终产生代理类的字节码文件:public static byte[] generateProxyClass(final String name, Class[] interfaces) { ProxyGenerator gen = new ProxyGenerator(name, interfaces); // 这里动态生成代理类的字节码 final byte[] classFile = gen.generateClassFile(); // 如果saveGeneratedFiles的值为true,则会把所生成的代理类的字节码保存到硬盘上 if (saveGeneratedFiles) { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<Void>() { public Void run() { try { FileOutputStream file = new FileOutputStream(dotToSlash(name) + ".class"); file.write(classFile); file.close(); return null; } catch (IOException e) { throw new InternalError( "I/O exception saving generated file: " + e); } } }); } // 返回代理类的字节码 return classFile; } 那么最终生成的代理类到底是什么样子呢,如下(省略了一下equals,hashcode,toString等方法,只展示构造函数和add方法):

  1. public final class $Proxy11 extends Proxy implements Service
  2. {
  3. // 构造方法,参数就是刚才传过来的MyInvocationHandler类的实例
  4. public $Proxy11(InvocationHandler invocationhandler)
  5. {
  6. super(invocationhandler);
  7. }
  8. /**
  9. * 继承的add方法,重写,调用MyInvocationHandler中的invoke方法
  10. */
  11. public final void add()
  12. {
  13. try
  14. {
  15. // 实际上就是调用MyInvocationHandler中的invoke方法
  16. super.h.invoke(this, m3, null);
  17. return;
  18. }
  19. catch(Error _ex) { }
  20. catch(Throwable throwable)
  21. {
  22. throw new UndeclaredThrowableException(throwable);
  23. }
  24. }
  25. }
注意:java的jdk中得动态代理有一个限制条件,就是必须要被代理的类基于统一的接口,否则不能够实现。如果必须要使代理突破这个限制,那么可以尝试运用cglib来实现动态代理。cglib能够使方法执行更加高效,但是可能在动态创建类的过程中效率会稍微低一些,缓存该过程生成的类即可。

读书人网 >编程

热点推荐