动态代理的使用和实现机制

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

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

动态代理运行机制:

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

1.代理接口:Moveable.java

package com.test;

public interface Moveable {

       void move();

}


2.被代理对象:Tank.java
package com.test;

import java.util.Random;

public class Tank implements Moveable {

    public void move() {
         System.out.println("Tank moving...");
         try {
             Thread.sleep(new Random().nextInt(10000));
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
     }

}

3.为被代理对象产生一个代理类对象,其中是想增加记录运行时间的功能

package com.test;

import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;

public class Proxy {
     public static Object newProxyInstance(Class interfaces,InvocationHandler h)throws Exception{
         StringBuffer methodStr = new StringBuffer();
         String tr = "\r\n";
         Method[] methods = interfaces.getMethods();
         //拼接代理类的方法
         for (Method method : methods) {
             methodStr.append(
             "    public "+ method.getReturnType()+ " " +method.getName()+"() {" + tr +
             "        try {" + tr +
             "            java.lang.reflect.Method md = " + interfaces.getName() + "." + "class.getMethod(\""  + method.getName() + "\");" + tr +
             "            h.invoke(this,md);" + tr +
             "        }catch(Exception e) {e.printStackTrace();}" + tr +
             "    }" + tr
             );
         }

         //拼接代理类
         String src = "package com.test;" + tr +
         "import com.test.Moveable;" + tr +
         "public class TimeProxy implements " + interfaces.getName() + " {" + tr +
         "    private com.test.InvocationHandler h;" + tr +
         "    public TimeProxy(com.test.InvocationHandler h) {" + tr +
         "        this.h = h;" + tr +
         "    }" + tr +
         methodStr.toString() + tr +
         "}";
         //创建代理类
         String fileName = System.getProperty("user.dir") + "/src/com/test/TimeProxy.java";
         File file = new File(fileName);
         FileWriter writer = new FileWriter(file);
         writer.write(src);
         writer.flush();
         writer.close();
         //编译
         JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
         StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
         Iterable units = fileMgr.getJavaFileObjects(fileName);
         CompilationTask ct = compiler.getTask(null, fileMgr, null, null, null, units);
         ct.call();
         fileMgr.close();
         //加载类到内存:
         Class c = ClassLoader.getSystemClassLoader().loadClass("com.test.TimeProxy");
         Constructor constructor = c.getConstructor(InvocationHandler.class); //得到参数为InvocationHandler类型的构造方法
         Object m = constructor.newInstance(h); //通过该构造方法得到实例
         return m;

     }
}

4.TankProxy.java

package com.test;

import java.lang.reflect.Method;

public class TankProxy {
     public static <T> T getBean(final Object tank) throws Exception{
         return (T)Proxy.newProxyInstance(tank.getClass().getInterfaces()[0], new InvocationHandler(){
             public void invoke(Object proxy, Method method) {
                 long start = System.currentTimeMillis();
                 System.out.println("start:"+start);
                 try {
                     method.invoke(tank, new Object[]{});
                 } catch (Exception e) {
                     e.printStackTrace();
                 }
                 long end = System.currentTimeMillis();
                 System.out.println("end:"+end);
                 System.out.println("time:"+(end-start));
             }

         });
     }
}

5.测试程序:

package com.test;

import java.util.List;

import com.extend.Tank2;
import com.extend.Tank3;
import com.juhe.LogProxy;
import com.juhe.TimeProxy;

public class Test {
     public static void main(String[] args) throws Exception {
         Tank tank = new Tank();
         Moveable m =  TankProxy.getBean(tank);
         m.move();

     }

}



执行该程序的结果为:
start:1369121253400
Tank moving...
end:1369121260078
time:6678



动态生成的代理类的内容如下:

package com.test;
import com.test.Moveable;
public class TimeProxy implements com.test.Moveable {
     private com.test.InvocationHandler h;
     public TimeProxy(com.test.InvocationHandler h) {
         this.h = h;
     }
     public void move() {
         try {
             java.lang.reflect.Method md = com.test.Moveable.class.getMethod("move");
             h.invoke(this,md);
         }catch(Exception e) {e.printStackTrace();}
     }

}

 

posted @ 2018-03-01 16:15  忆南兮  阅读(162)  评论(0编辑  收藏  举报