源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

深入解析java中的静态代理与动态代理

  • 时间:2020-02-27 20:27 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:深入解析java中的静态代理与动态代理
java编码中经常用到代理,代理分为静态代理和动态代理。其中动态代理可以实现spring中的aop。 [b]一、静态代理:[/b]程序运行之前,程序员就要编写proxy,然后进行编译,即在程序运行之前,代理类的字节码文件就已经生成了 [b]被代理类的公共父类 [/b]
[u]复制代码[/u] 代码如下:
package staticproxy; public abstract class BaseClass {     public abstract void add(); }
[b]被代理类 [/b]
[u]复制代码[/u] 代码如下:
package staticproxy; public class A extends BaseClass {     public void add() {         System.out.println("A add !");     } }
[b]代理类 [/b]
[u]复制代码[/u] 代码如下:
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();     } }
[b]二、动态代理:[/b]实际的代码在编译期间并没有生成,而是在运行期间运用反射机制动态的生成 [b]被代理类接口 [/b]
[u]复制代码[/u] 代码如下:
package jdkproxy; public interface Service {     public void add();     public void update(); }
[b]被代理类A [/b]
[u]复制代码[/u] 代码如下:
package jdkproxy; public class AService implements Service {     public void add() {         System.out.println("AService add>>>>>>>>>>>>>>>>>>");     }     public void update() {         System.out.println("AService update>>>>>>>>>>>>>>>");     } }
[b]被代理类B [/b]
[u]复制代码[/u] 代码如下:
package jdkproxy; public class BService implements Service {     public void add() {         System.out.println("BService add---------------");     }     public void update() {         System.out.println("BService update---------------");     } }
[b]代理类 [/b]
[u]复制代码[/u] 代码如下:
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;     } }
测试类
[u]复制代码[/u] 代码如下:
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()方法。 [b]下面详细介绍是如何实现代理对象的生成的[/b] Proxy的newProxyInstance方法,其中,为了看起来方便,已经将该方法中的异常处理语句删减 下下面public static Object newProxyInstance(ClassLoader loader,  Class<?>[] interfaces,InvocationHandler h) throws
[u]复制代码[/u] 代码如下:
    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方法
[u]复制代码[/u] 代码如下:
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方法,该方法最终产生代理类的字节码文件:
[u]复制代码[/u] 代码如下:
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方法):
[u]复制代码[/u] 代码如下:
public final class $Proxy11 extends Proxy implements Service  {      // 构造方法,参数就是刚才传过来的MyInvocationHandler类的实例      public $Proxy11(InvocationHandler invocationhandler)      {          super(invocationhandler);      }      /**      * 继承的add方法,重写,调用MyInvocationHandler中的invoke方法      */      public final void add()      {          try          {              // 实际上就是调用MyInvocationHandler中的invoke方法              super.h.invoke(this, m3, null);              return;          }          catch(Error _ex) { }         catch(Throwable throwable)          {              throw new UndeclaredThrowableException(throwable);          }     }  } 
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部