jdk动态代理原理

来源:互联网 发布:java queue线程安全 编辑:程序博客网 时间:2024/05/16 01:46

动态代理实现思路:

Moveable m = (Moveable) Proxy.newProxyInstance(ClassLoader, Interfaces, InvocationHandler);

 实现功能:通过Proxy的newProxyInstance返回代理对象
                   * 1.声明一段源码(动态产生代理)
                   * 2.编译源码(JDK Compiler API),产生新的类(代理类)
                   * 3.将这个类load到内存当中,产生一个新的对象(代理对象)
                   * 4.return 代理对象
 
 由于对实现接口的任意对象的任意方法进行代理

1.Proxy.java:

package com.zy.proxyPrinciple;import java.io.File;import java.io.IOException;import java.lang.reflect.Method;import org.apache.commons.io.FileUtils;public class Proxy {public static Object newProxyInstance(Class infce) throws Exception {// windows下的换行符String rt = "\r\n";//获取类中的所有方法String methodStr = "";for (Method m : infce.getMethods()) {methodStr += "@Override"+ rt+ "public void "+m.getName()+"() {"+ rt+ "long starttime = System.currentTimeMillis();"+ rt+ "System.out.println(\"汽车开始行驶...\");"+ rt+ "m."+m.getName()+"();"+ rt+ "long endtime = System.currentTimeMillis();"+ rt+ "System.out.println(\"汽车结束行使..\" + (endtime - starttime) + \"毫秒\");"+ rt +"}" ;}// 源码// 返回的动态代理类(CarTimeProxy.java),注意"要用转义字符\,每行末尾加rt换行,jdk生成代理类、构造函数名字为$Proxy0String str ="package com.zy.proxyPrinciple;"+ rt+"public class $Proxy0 implements "+infce.getName()+" {"+ rt+"public $Proxy0("+infce.getName()+" m) {"+ rt+ "super();"+ rt+                "this.m = m;"+ rt+                 "}"+ rt+"private "+infce.getName()+" m;"+ rt+     methodStr + rt +"}";// 先创建java文件放置到对应的文件目录,再编译此java文件// 获得当前的路径// 放在bin目录下方便编译String filename = System.getProperty("user.dir")+ "/bin/com/zy/proxyPrinciple/$Proxy.java";File file = new File(filename);// 引入jar包,commons-io.jar,提供FileUtils快速写入内容到文件中FileUtils.writeStringToFile(file, str);return null;}}

2.Test.java:

package com.zy.proxyPrinciple;public class Test {public static void main(String[] args) throws Exception {Proxy.newProxyInstance(Moveable.class);}}

3.将代理业务抽取出来对任意对象的任意方法起作用,动态的实现业务逻辑
   创建事务处理器:


  1> InvocationHandler.java接口:

package com.zy.proxyPrinciple;import java.lang.reflect.Method;public interface InvocationHandler {public void invoke(Object o, Method m);}

  2>TimeHandler.java接口实现类:(把Proxy.java中写死的业务代码提取到相应的业务处理类)

package com.zy.proxyPrinciple;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class TimeHandler implements InvocationHandler {// 获取被代理类private Object target;public TimeHandler(Object target) {super();this.target = target;}@Overridepublic void invoke(Object o, Method m) {try {long starttime = System.currentTimeMillis();System.out.println("汽车开始行驶...");// 调用代理类的方法m.invoke(target);long endtime = System.currentTimeMillis();System.out.println("汽车结束行使.." + (endtime - starttime) + "毫秒");} catch (Exception e) {e.printStackTrace();}}}

  3>修改Proxy.java,将代理业务处理类作为参数传入代理对象
       源码中创建InvocationHandler,并且import进来,import Method进来


package com.zy.proxyPrinciple;import java.io.File;import java.io.IOException;import java.lang.reflect.Constructor;import java.lang.reflect.Method;import javax.tools.JavaCompiler;import javax.tools.JavaCompiler.CompilationTask;import javax.tools.StandardJavaFileManager;import javax.tools.ToolProvider;import org.apache.commons.io.FileUtils;public class Proxy {public static Object newProxyInstance(Class infce,<span style="color:#ff6666;">InvocationHandler h</span>) throws Exception {// windows下的换行符String rt = "\r\n";//获取类中的所有方法String methodStr = "";for (Method m : infce.getMethods()) {methodStr += "@Override"+ rt+ "public void "+m.getName()+"() {"+ rt+ "try{"+ rt+ <span style="color:#ff6666;">"Method md = "+infce.getName() +".class.getMethod(\""            +m.getName()+"\");"+ rt+ "h.invoke(this,md);"+ rt+</span>"}catch(Exception e){e.printStackTrace();}"+ rt+"}" ;}// 源码// 返回的动态代理类(CarTimeProxy.java),注意"要用转义字符\,每行末尾加rt换行,jdk生成代理类、构造函数名字为$Proxy0String str ="package com.zy.proxyPrinciple;"+ rt+<span style="color:#ff6666;">"import com.zy.proxyPrinciple.InvocationHandler;"+ rt+                "import java.lang.reflect.Method;"+ rt+</span>"public class $Proxy0 implements "+infce.getName()+" {"+ rt+"public $Proxy0(InvocationHandler h) {"+ rt+ "super();"+ rt+                                "this.h = h;"+ rt+                 "}"+ rt+<span style="color:#ff6666;">"private InvocationHandler h;"+ rt+</span>         methodStr + rt +"}";// 1、产生代理类的java文件// 获得当前的路径// 放在bin目录下方便编译String filename = System.getProperty("user.dir")+ "/bin/com/zy/proxyPrinciple/$Proxy0.java";File file = new File(filename);// 引入jar包,commons-io.jar,提供FileUtils快速写入内容到文件中FileUtils.writeStringToFile(file, str);//2、编译代理类的java文件//拿到编译器JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();//文件管理者StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null,null,null);//获取文件Iterable utils = fileMgr.getJavaFileObjects(filename);//编译任务//参数:输出位置,fileMgr,监听器,国际化参数,国际化参数,要编译的文件CompilationTask t = compiler.getTask(null,fileMgr,null,null,null,utils);//进行编译t.call();fileMgr.close();//3、编译好的文件load到内存中ClassLoader cl = ClassLoader.getSystemClassLoader();Class c = cl.loadClass("com.zy.proxyPrinciple.$Proxy0");                 //4、根据代理类的构造方法创建代理类并返回Constructor ctr = c.getConstructor(<span style="color:#ff6666;">InvocationHandler.class</span>);<span style="color:#ff6666;">return ctr.newInstance(h);</span>}}

  4>测试类:Test.java

package com.zy.proxyPrinciple;public class Test {public static void main(String[] args) throws Exception {Car car = new Car();InvocationHandler h = new TimeHandler(car);Moveable m = (Moveable) Proxy.newProxyInstance(Moveable.class, h);m.move();}}



具体思路:

Proxy.java:声明动态源码,产生动态代理 --> 源码生成java文件 --> 对java文件进行编译 --> 将编译好的java文件load到内存中 --> 产生代理类的对象 

Test.java: 定义一个InvocationHandler专门进行代理业务处理(计时功能、日志功能等) --> 产生代理对象时把InvocationHandler传进去
           
面向切面编程(InvocationHandler): 在方法的前后增加逻辑处理


  



0 0
原创粉丝点击