Java-马士兵设计模式学习笔记-代理模式-动态代理 修改成可以任意修改代理逻辑
2015-06-22 14:45
981 查看
一、概述
1.目标:动态代理的代理逻辑可以任意修改
2.思路:
(1)要把代理逻辑抽离,站在jvm的角度思考,应独立出InvocationHandler接口,并接收被代理的对象及方法作为参数invoke(Object o, Method m),并本身作为参数传给newProxyInstance(Class interfze,InvocationHandler handler)
(2)InvocationHandler本身聚合被代理类target,以便在target的方法前后增加代理逻辑
3.知识点:
(1)按名字找方法java.lang.reflect.Method md = proxy.Movable.class.getMethod("stop");
(2)按"."拆分字符串:String [] parts = m.toString().replace("abstract ", "").split("\\.");
二、代码
1.InvocationHandler.java
2.TimeHandler.java
3.Movable.java
4.Tank.java
5.Proxy.java
6.Client.java
1.InvocationHandler.java
2.TimeHandler.java
3.Movable.java
4.Tank.java
5.Proxy.java
6.Client.java
三、运行结果
1.目标:动态代理的代理逻辑可以任意修改
2.思路:
(1)要把代理逻辑抽离,站在jvm的角度思考,应独立出InvocationHandler接口,并接收被代理的对象及方法作为参数invoke(Object o, Method m),并本身作为参数传给newProxyInstance(Class interfze,InvocationHandler handler)
(2)InvocationHandler本身聚合被代理类target,以便在target的方法前后增加代理逻辑
3.知识点:
(1)按名字找方法java.lang.reflect.Method md = proxy.Movable.class.getMethod("stop");
(2)按"."拆分字符串:String [] parts = m.toString().replace("abstract ", "").split("\\.");
二、代码
1.InvocationHandler.java
2.TimeHandler.java
3.Movable.java
4.Tank.java
5.Proxy.java
6.Client.java
1.InvocationHandler.java
package proxy; import java.lang.reflect.Method; public interface InvocationHandler { public void invoke(Object o, Method m); }
2.TimeHandler.java
package proxy; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class TimeHandler implements InvocationHandler { //保留被代理的对象 private Object target; public TimeHandler(Object target) { this.target = target; } @Override public void invoke(Object o, Method m) { System.out.println("Time Proxy start..........."); long start = System.currentTimeMillis(); try { //除了静态方法,方法的调用都要先已知对象,所以要把对象o作为参数传进去 m.invoke(target); } catch (Exception e) { e.printStackTrace(); } long end = System.currentTimeMillis(); System.out.println("花费时间:"+(end - start)); System.out.println("Time Proxy end..........."); } }
3.Movable.java
package proxy; public interface Movable { public void move(); public void stop(); }
4.Tank.java
package proxy; import java.util.Random; public class Tank implements Movable { @Override public void move() { System.out.println("Tank moving......."); try { Thread.sleep(new Random().nextInt(2000)); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public void stop() { System.out.println("Tank stopping......."); } }
5.Proxy.java
package proxy; import java.io.File; import java.io.FileWriter; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import javax.tools.JavaCompiler; import javax.tools.JavaCompiler.CompilationTask; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; public class Proxy { public static Object newProxyInstance(Class interfze,InvocationHandler handler) throws Exception { String rt = "\n\r"; //拼接"实现接口方法"的字符串 String methodStr = ""; for(Method m: interfze.getMethods() ){ //取出方法的修饰符和返回值类型 String [] parts = m.toString().replace("abstract ", "").split("\\."); String [] parts2 = parts[0].split(" "); methodStr += "@Override" + rt + parts2[0]+" "+parts2[1]+" "+m.getName()+"() {" + rt + "try{"+ rt + "java.lang.reflect.Method md = " + interfze.getName() + ".class.getMethod(\""+m.getName()+"\");" + rt + //传this进去其实没什么用,invoke实际是调用target的方法m.invoke(target) "handler.invoke(this, md);" + rt + "}catch(Exception e){"+ rt + " e.printStackTrace();" + rt + "}" + rt + "}"+ rt ; } //动态代理文件的源码 String str = "package proxy;" + rt + "public class TankTimeProxy implements " + interfze.getName() + " {"+rt+ //聚合Handler "private InvocationHandler handler;" + rt + "public TankTimeProxy(InvocationHandler handler) {" + rt + "this.handler = handler;" + rt + "}" + rt + methodStr + rt + "}" ; //把源码写到java文件里 File file = new File(System.getProperty("user.dir")+"/src/proxy/TankTimeProxy.java"); FileWriter fw = new FileWriter(file); fw.write(str); fw.flush(); fw.close(); //编译源码,生成class,注意编译环境要换成jdk才有compiler,单纯的jre没有compiler,会空指针错误 JavaCompiler jc = ToolProvider.getSystemJavaCompiler(); //文件管事器 StandardJavaFileManager fileMgr = jc.getStandardFileManager(null, null, null); //编译单元 Iterable units = fileMgr.getJavaFileObjects(file); //编译任务 CompilationTask t = jc.getTask(null, fileMgr, null, null, null, units); //编译 t.call(); fileMgr.close(); //把类load到内存里 URL[] urls = new URL[] {new URL("file:/"+System.getProperty("user.dir")+"/src/proxy/TankTimeProxy.class")}; URLClassLoader uc = new URLClassLoader(urls); Class c = uc.loadClass("proxy.TankTimeProxy"); //生成实例 //return c.newInstance(); //c.newInstance()会调用无参数的Construtor,若类没有无参的Constructor时会出错 //Constructor ctr = c.getConstructor(interfze); Constructor ctr = c.getConstructor(InvocationHandler.class); return ctr.newInstance(handler); } }
6.Client.java
package proxy; import java.io.IOException; import org.junit.Test; public class Client { @Test public void testProxy() throws Exception{ Movable m = (Movable)Proxy.newProxyInstance(Movable.class, new TimeHandler(new Tank())); m.move(); m.stop(); } }
三、运行结果
相关文章推荐
- Java的一些概念整理
- Java之美[从菜鸟到高手演变]之设计模式四
- Java之美[从菜鸟到高手演变]之设计模式三
- java 中多线程的同步函数的运用
- Java之美[从菜鸟到高手演变]之设计模式二
- Java之美[从菜鸟到高手演变]之设计模式
- Java之美[从菜鸟到高手演变]之智力题【史上最全】
- Java线程基础学习
- ubuntu14.04 安装jdk
- 做java项目时遇到的错误
- java基础知识(2015,6,22)
- Java 输入输出流
- RandomAccessFileDemo
- Java基础:面向对象三大特征、五大原则
- 导入时如何定制spring-boot依赖项的版本
- java基础—文件的切割与合并
- mysql数据源spring配置
- Struts的中文filter
- java枚举小结
- JAVA抽象类和接口的深入探讨