zoukankan      html  css  js  c++  java
  • 动态代理的使用和实现机制

    工作中很久没有接触动态代理,之前的学习也有些模糊,导致有些遗忘,这里记录下个人对动态代理的理解,如有读者发现问题多多指正吧。

    就java而言对于动态代理的支持多是以接口实现,其实现主要是通过java.lang.reflect.Proxy类,java.lang.reflect.InvocationHandler接口。Proxy类主要用于获取动态代理对象,InvocationHandler接口用来约束调用者实现。

    动态代理运行机制:

    Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)方法会返回一个代理对象类的实例。当程序执行时会通过反射机制动态的生成一个代理类,该类实现一个接口里的方法(也就是说代理类与被代理类有相同的接口),在该代理类里面有一个InvocationHandler类型的成员变量,也就是调用处理程序,通过调用处理程序来给被代理类增强功能。创建好代理类后就调用类加载器将该类加载到类存,然后再通过反射创建一个该代理类的实例对象。下面是具体实现:

      1 1.代理接口:Moveable.java
      2 
      3 package com.test;
      4 
      5 public interface Moveable {
      6 
      7        void move();
      8 
      9 }
     10 
     11 
     12 2.被代理对象:Tank.java
     13 package com.test;
     14 
     15 import java.util.Random;
     16 
     17 public class Tank implements Moveable {
     18 
     19     public void move() {
     20          System.out.println("Tank moving...");
     21          try {
     22              Thread.sleep(new Random().nextInt(10000));
     23          } catch (InterruptedException e) {
     24              e.printStackTrace();
     25          }
     26      }
     27 
     28 }
     29 
     30 3.为被代理对象产生一个代理类对象,其中是想增加记录运行时间的功能
     31 
     32 package com.test;
     33 
     34 import java.io.File;
     35 import java.io.FileWriter;
     36 import java.lang.reflect.Constructor;
     37 import java.lang.reflect.Method;
     38 
     39 import javax.tools.JavaCompiler;
     40 import javax.tools.StandardJavaFileManager;
     41 import javax.tools.ToolProvider;
     42 import javax.tools.JavaCompiler.CompilationTask;
     43 
     44 public class Proxy {
     45      public static Object newProxyInstance(Class interfaces,InvocationHandler h)throws Exception{
     46          StringBuffer methodStr = new StringBuffer();
     47          String tr = "
    ";
     48          Method[] methods = interfaces.getMethods();
     49          //拼接代理类的方法
     50          for (Method method : methods) {
     51              methodStr.append(
     52              "    public "+ method.getReturnType()+ " " +method.getName()+"() {" + tr +
     53              "        try {" + tr +
     54              "            java.lang.reflect.Method md = " + interfaces.getName() + "." + "class.getMethod(""  + method.getName() + "");" + tr +
     55              "            h.invoke(this,md);" + tr +
     56              "        }catch(Exception e) {e.printStackTrace();}" + tr +
     57              "    }" + tr
     58              );
     59          }
     60 
     61          //拼接代理类
     62          String src = "package com.test;" + tr +
     63          "import com.test.Moveable;" + tr +
     64          "public class TimeProxy implements " + interfaces.getName() + " {" + tr +
     65          "    private com.test.InvocationHandler h;" + tr +
     66          "    public TimeProxy(com.test.InvocationHandler h) {" + tr +
     67          "        this.h = h;" + tr +
     68          "    }" + tr +
     69          methodStr.toString() + tr +
     70          "}";
     71          //创建代理类
     72          String fileName = System.getProperty("user.dir") + "/src/com/test/TimeProxy.java";
     73          File file = new File(fileName);
     74          FileWriter writer = new FileWriter(file);
     75          writer.write(src);
     76          writer.flush();
     77          writer.close();
     78          //编译
     79          JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
     80          StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
     81          Iterable units = fileMgr.getJavaFileObjects(fileName);
     82          CompilationTask ct = compiler.getTask(null, fileMgr, null, null, null, units);
     83          ct.call();
     84          fileMgr.close();
     85          //加载类到内存:
     86          Class c = ClassLoader.getSystemClassLoader().loadClass("com.test.TimeProxy");
     87          Constructor constructor = c.getConstructor(InvocationHandler.class); //得到参数为InvocationHandler类型的构造方法
     88          Object m = constructor.newInstance(h); //通过该构造方法得到实例
     89          return m;
     90 
     91      }
     92 }
     93 
     94 4.TankProxy.java
     95 
     96 package com.test;
     97 
     98 import java.lang.reflect.Method;
     99 
    100 public class TankProxy {
    101      public static <T> T getBean(final Object tank) throws Exception{
    102          return (T)Proxy.newProxyInstance(tank.getClass().getInterfaces()[0], new InvocationHandler(){
    103              public void invoke(Object proxy, Method method) {
    104                  long start = System.currentTimeMillis();
    105                  System.out.println("start:"+start);
    106                  try {
    107                      method.invoke(tank, new Object[]{});
    108                  } catch (Exception e) {
    109                      e.printStackTrace();
    110                  }
    111                  long end = System.currentTimeMillis();
    112                  System.out.println("end:"+end);
    113                  System.out.println("time:"+(end-start));
    114              }
    115 
    116          });
    117      }
    118 }
    119 
    120 5.测试程序:
    121 
    122 package com.test;
    123 
    124 import java.util.List;
    125 
    126 import com.extend.Tank2;
    127 import com.extend.Tank3;
    128 import com.juhe.LogProxy;
    129 import com.juhe.TimeProxy;
    130 
    131 public class Test {
    132      public static void main(String[] args) throws Exception {
    133          Tank tank = new Tank();
    134          Moveable m =  TankProxy.getBean(tank);
    135          m.move();
    136 
    137      }
    138 
    139 }
    140 
    141 
    142 
    143 执行该程序的结果为:
    144 start:1369121253400
    145 Tank moving...
    146 end:1369121260078
    147 time:6678
    148 
    149 
    150 
    151 动态生成的代理类的内容如下:
    152 
    153 package com.test;
    154 import com.test.Moveable;
    155 public class TimeProxy implements com.test.Moveable {
    156      private com.test.InvocationHandler h;
    157      public TimeProxy(com.test.InvocationHandler h) {
    158          this.h = h;
    159      }
    160      public void move() {
    161          try {
    162              java.lang.reflect.Method md = com.test.Moveable.class.getMethod("move");
    163              h.invoke(this,md);
    164          }catch(Exception e) {e.printStackTrace();}
    165      }
    166 
    167 }

    小结:动态代理在运行期通过接口动态生成代理类,这为其带来了一定的灵活性,但这个灵活性却带来了两个问题,第一代理类必须实现一个接口,如果没实现接口会抛出一个异常。第二性能影响,因为动态代理使用反射的机制实现的,首先反射肯定比直接调用要慢,其次使用反射大量生成类文件可能引起Full GC造成性能影响,因为字节码文件加载后会存放在JVM运行时区的方法区(或者叫持久代)中,当方法区满的时候,会引起Full GC,所以当你大量使用动态代理时,可以将持久代设置大一些,减少Full GC次数。

    引用前者:残剑

  • 相关阅读:
    2017-2018-2 20155234『网络对抗技术』Exp5:MSF基础应用
    20155234 exp4 恶意代码分析
    20155234 Exp3 免杀原理与实践
    20155234 Exp2 后门原理与实践
    20155234 昝昕明 《网络对抗技术》实验一 PC平台逆向破解
    20165232 第二周学习总结
    # 2017-2018-2 20155231《网络对抗技术》实验九: Web安全基础实践
    2017-2018-2 20155231《网络对抗技术》实验八: WEB基础实验
    2017-2018-2 20155231《网络对抗技术》实验五: MSF基础应用
    2017-2018-2 20155231《网络对抗技术》实验七: 网络欺诈防范
  • 原文地址:https://www.cnblogs.com/ldy-blogs/p/8480059.html
Copyright © 2011-2022 走看看