继承?静态代理?写一个自己的动态代理吧
来源:互联网 发布:淘宝助理有客服吗 编辑:程序博客网 时间:2024/06/11 09:32
[ 需求分析 ]
在我们实际开发中常常会遇到这样的问题:记录一个类的方法运行时间,以分析性能。一般我们的做法是先在类的开始记录一个开始时间,然后在类的结束记录一个结束时间,二者相减就可以获取我们想要的结果。但是很多时候这些类已经打了jar包,我们无法直接修改源码,这个时候我们应该怎么办呢?
下文使用Tank的移动需要统计时间、记录日志来模拟需求场景,假定Moveable、Tank类无法修改。
interface:Moveable
public interface Moveable {public void move();}
realization:Tank
public class Tank implements Moveable{public void move() {System.out.println("tank is moving");}}
[ 继承实现 ]
① 现在我们假设需要统计Tank移动的时间,通过实现Tank,并加入统计时间的代码即可做到import java.util.Random;/** * use to record tank move time * @author zhangjim */public class TankTimeProxy extends Tank {public void move() {try {long start = System.currentTimeMillis();super.move();// make the tank move solwlyThread.sleep(new Random().nextInt(1000)); long end = System.currentTimeMillis();System.out.println("total spend time: " + (end - start) + "ms");} catch (Exception e) {e.printStackTrace();}}}② 测试代码:
/** * test client * @author zhangjim */public class Client {public static void main(String[] args) {Moveable m = new TankTimeProxy();m.move();}}③ 分析:
上述方法可以解决我们的问题,但如果现在需要增加需求:加入日志记录功能,那么我们就要再继承TankTimeProxy
/** * use to record tank move logs * @author zhangjim */public class TankLogProxy extends TankTimeProxy{public void move() {System.out.println("tank start to move...");super.move();System.out.println("tank stop to move...");}}这种实现方法存在一个很大的缺陷:很不灵活,如果后期还要加功能的话,就要不断的继承下去,父子关系过于臃肿,不利于维护。
[ 静态代理 ]
① 接上文,现在我们使用静态代理实现上面的功能:
重写TankTimeProxy:
import java.util.Random;/** * use to record tank move time * @author zhangjim */public class TankTimeProxy implements Moveable {private Moveable m;public TankTimeProxy(Moveable m) {this.m = m;}@Overridepublic void move() {try {long start = System.currentTimeMillis();m.move();Thread.sleep(new Random().nextInt(1000));long end = System.currentTimeMillis();System.out.println("total spend time: " + (end - start) + "ms");} catch (Exception e) {e.printStackTrace();}}}
/** * use to record tank move logs * @author zhangjim */public class TankLogProxy implements Moveable{private Moveable m;public TankLogProxy(Moveable m) {this.m = m;}@Overridepublic void move() {System.out.println("tank start to move...");m.move();System.out.println("tank stop to move...");}}
② 测试一下吧
/** * test client * @author zhangjim */public class Client {public static void main(String[] args) {Moveable m = new TankLogProxy(new TankTimeProxy(new Tank()));m.move();}}
③ 分析:
通过代码不难看出,代理类和被代理类实现了同一个接口,其实这个就是装饰设计模式。相对于继承,聚合的类结构无疑更方便管理和维护,但是它仍然有一个弊病:对于不同的功能,我仍然需要加类。例如:加权限控制功能需要TankAuthorityProxy,加事务控制功能需要TankTransactionProxy等等,能不能让计算机帮我们产生这些类?自己动手试试吧!
[ 我的动态代理 ]
① 所谓的动态代理,就是说上文的TankTimeProxy,TankLogProxy不需要我们手动创建了,计算机会帮我们动态生成,也就是说这个代理类不是提前写好的,而是程序运行时动态生成的。
我们写一个proxy类,它的作用就是帮我们产生代理类。
主要实现思路:
i 将所有方法代码拼接成字符串。
ii 将生成代理类的代码拼接成字符串(包含所有方法拼接成的字符串)。
iii 将此字符串写入文件中、并使用JavaComplier对它进行编译。
Ⅳ 将编译好的文件load进内存供我们使用,并返回代理实例。
public class Proxy {public static Object newProxyInstance(Class intefc, InvocationHandler handle) throws Exception {String rt = "\r\t" ;String methodStr = "" ;// first we should realize all the methods of the interfaceMethod[] methods = intefc.getMethods();for (Method m : methods) {methodStr +="public void "+m.getName()+"(){"+rt+" try{"+rt+" Method method = "+intefc.getName()+".class.getMethod(\""+m.getName()+"\");" + rt +" handle.invoke(this,method);" +rt+" }catch(Exception ex){}" +rt+"}" ;}String clazzStr = "package com.zdp.dynamicProxy;"+rt+ "import java.lang.reflect.Method;"+rt+ "public class $Proxy1 implements "+intefc.getName()+"{"+rt+ " private com.zdp.dynamicProxy.InvocationHandler handle ;"+rt+ " public $Proxy1(InvocationHandler handle){"+rt+ " this.handle=handle;"+rt+ " }"+rt+ " @Override"+rt+ methodStr +rt+ "}";// write to a java file File file = new File("D:/develop_environment/babasport/homework/src/com/zdp/dynamicProxy/$Proxy1.java") ;FileWriter writer = null ;try {writer = new FileWriter(file);writer.write(clazzStr) ;writer.flush() ;} catch (IOException e) {e.printStackTrace();}finally{try {if(writer !=null){writer.close() ;}} catch (IOException e) {e.printStackTrace();}}//load the java file, and then create an instance URL[] urls = new URL[] {new URL("file:/" + "D:/develop_environment/babasport/homework/src/")};URLClassLoader urlLoader = new URLClassLoader(urls);Class c = urlLoader.loadClass("com.zdp.dynamicProxy.$Proxy1");//return the proxy instanceConstructor ctr = c.getConstructor(InvocationHandler.class);Object proxyInstance = ctr.newInstance(handle);return proxyInstance;}}② 因为要处理所有的业务,我们定义一个接口InvocationHandler
public interface InvocationHandler {public void invoke(Object o, Method m) ; }
③ MyHandler是真正的处理类
/** * use to record logs and time * @author zhangjim */public class MyHandler implements com.zdp.dynamicProxy.InvocationHandler {private Object target;public MyHandler(Object target) {this.target = target;}public void invoke(Object obj, Method method) {try {System.out.println("tank start to move...");long start = System.currentTimeMillis();method.invoke(target);Thread.sleep(new Random().nextInt(1000));long end = System.currentTimeMillis();System.out.println("total spend time: " + (end - start) + "ms");System.out.println("tank stop to move...");} catch (Exception e) {e.printStackTrace();}}}④ Proxy类会帮我们动态创建一个类$Proxy1
public class $Proxy1 implements com.zdp.dynamicProxy.Moveable {private com.zdp.dynamicProxy.InvocationHandler handle;public $Proxy1(InvocationHandler handle) {this.handle = handle;}@Overridepublic void move() {try {Method method = com.zdp.dynamicProxy.Moveable.class.getMethod("move");handle.invoke(this, method);} catch (Exception ex) {}}}
⑤ 测试一下,看看效果怎么样
/** * test client * @author zhangjim */public class Client {public static void main(String[] args) throws Exception {Moveable m = new Tank();InvocationHandler handle = new MyHandler(m);Moveable proxy = (Moveable) Proxy.newProxyInstance(Moveable.class, handle);proxy.move();}}
⑥ 简要总结:
Proxy:动态创建代理类,通过调用处理器的处理方法来实现代理。
InvocationHandler:实现对被代理对象的处理。
[ 应用场景 ]
① 系统日志记录② 权限控制(符合一定条件才执行某方法)
③ 事务控制(方法执行之前开启事务,方法执行之后提交或回滚事务)
[ 特别感谢 ]
这篇日志是对马士兵老师:《设计模式之动态代理》的一个总结,非常感谢马老师的辛勤工作。- 继承?静态代理?写一个自己的动态代理吧
- 代理模式——动态代理(自己写一个)
- 自己写的JDK动态代理类
- 代理-->静态代理&动态代理
- 动态代理,静态代理
- 静态代理 动态代理
- 静态代理/动态代理
- 静态代理&动态代理
- 静态代理&动态代理
- 静态代理 & 动态代理
- 静态代理&动态代理
- 动态代理,静态代理
- Spring的静态代理和动态代理
- 动态代理与静态代理的区别
- java的静态代理和动态代理
- 动态代理和静态代理的区别
- 动态代理和静态代理的比较
- Java 的静态代理和动态代理
- C#中的委托和事件
- jquery解析后台传的json数据
- Java中的泛型方法
- 扒一扒这个数据挖掘行业,黄油和面包
- ubuntu 下安装source insight
- 继承?静态代理?写一个自己的动态代理吧
- hdu 1074 状态压缩dp
- 粥中有道,读书笔记
- 微信公众平台通知插件,网店必备客户服务工具
- linux下安装mysql
- Socket通信原理
- time类
- 南阳理工OJ_题目891 找点
- nyoj119(RMQ算法+线段树)