设计模式(代理模式--动态代理)
2015-08-02 13:20
441 查看
动态代理可以动态的实现所有接口,这是静态代理所不能胜任的。
前一章静态代理类固定实现了Imove接口,现在我们将该Imove接口类通过java的反射机制拿到所有接口,循环遍历其接口做实现如下面代码:
执行以上代码输出:
开始时间
坦克在移动.....
结束时间
根据输出的内容,明显的动态的在坦克移动功能前后加上了其他业务处理逻辑。
其实以上Proxy类得功能就是实现动态生成代理类,这个类可以说是所有代理类的总代理。newProxyInstance方法中传入代理类实现的接口以及代理对象委托实现,通过java的反射机制拿到了实现接口的所有方法,循环遍历所有方法即可让代理对象实现接口的所有方法。这时代理类的java代码通过字符串拼接后写入到java类文件中。通过JDK自带的编译器JavaCompiler编译JAVA文件生成对应的class文件。通过类加载器加载到类存中生成对象返回给客户端。这样代理的功能就实现了,它的好处是能动态的实现接口中的所有方法。将主体核心的业务逻辑与公用的业务逻辑剥离开,比如需要计算代理对象运行了多长时间,在不改变核心业务代码的前提下就能在方法前后加上你的计算时间的代码。这段代码的功能与JDK1.6中的的代理实现机制一样,只是这里比JDK1.6中的简单一些。在spring中AOP面向切面编程也是代理的一种应用,这里的机制跟spring的机制也很像。spring生成class文件有两种生成方式
一种是JDK1.6中的编译,还有一种是cglib。cglib是不生成class文件,直接读入到类存中去。而jdk1.6的JavaCompiler是生成class编译文件,然后再通过classload加载进Jvm。
前一章静态代理类固定实现了Imove接口,现在我们将该Imove接口类通过java的反射机制拿到所有接口,循环遍历其接口做实现如下面代码:
//代理对象处理类 package com.study.proxy; import java.lang.reflect.Method; public interface InvocationHandler { public void invoke(Object o,Method m) throws Exception; }
//日志处理对象 package com.study.proxy.real; import java.lang.reflect.Method; import com.study.proxy.InvocationHandler; public class LogHandler implements InvocationHandler { private Object obj; public LogHandler(Object obj) { super(); this.obj = obj; } @Override public void invoke(Object o, Method m) throws Exception { System.out.println("开始时间"); m.invoke(obj); System.out.println("结束时间"); } }
//代理对象实现该接口 package com.study.proxy; public interface Imove { public void move(); }
//代理对象 package com.study.proxy; public class Tank implements Imove{ @Override public void move() { System.out.println("坦克在移动....."); } }
//总代理(代理类的生成) package com.study.proxy.real; import java.io.File; import java.io.FileWriter; import java.io.IOException; 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.StandardJavaFileManager; import javax.tools.ToolProvider; import javax.tools.JavaCompiler.CompilationTask; import com.study.proxy.Imove; import com.study.proxy.InvocationHandler; import com.study.proxy.Tank; public class Proxy { //第一个参数就是从外面传入的接口类,第二个参数就是代理对象处理 public static Object newProxyInstance(Class inface,InvocationHandler h) throws Exception { String rt="\r\n"; Method[] method=inface.getMethods(); String methodStr="" //通过java反射机制将接口对象中的所有方法拿到做循环实现 for(Method m:method){ methodStr=methodStr+ " public void "+m.getName()+"() {"+rt+ " try{"+rt+ " Method md="+inface.getName()+".class.getMethod(\""+m.getName()+"\");"+rt+ " h.invoke(this,md);"+rt+ " }catch(Exception ex){" +rt+ " }"+rt+
" }"+rt;
System.out.println(m.getName()); } //通过字符串拼接动态生成的代理类字符串 String str="package com.study.proxy.real;" +rt+ "import com.study.proxy.Imove;"+rt+ "import java.lang.reflect.Method;"+rt+ "import com.study.proxy.InvocationHandler;"+rt+ "public class TankMoveProxy implements " +inface.getName()+ " {"+rt+ " private InvocationHandler h;"+rt+ " public TankMoveProxy(InvocationHandler hander) {"+rt+ " super();"+rt+ " this.h = hander;"+rt+ " }"+rt+methodStr+ "}"; String fileName = System.getProperty("user.dir") + "/src/com/study/proxy/real/TankMoveProxy.java"; //将动态生成代理类java代码写入指定的文件中 File f = new File(fileName); FileWriter fw = new FileWriter(f); fw.write(str); fw.flush(); fw.close(); //编译生成的java类文件生成对应的class文件 JavaCompiler jc = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager sjf = jc.getStandardFileManager(null, null, null); Iterable iter = sjf.getJavaFileObjects(fileName); CompilationTask ct = jc.getTask(null, sjf, null, null, null, iter); ct.call(); sjf.close(); //加载生成的class文件到内存中 URL[] urls = new URL[] { new URL("file:/" + System.getProperty("user.dir") + "/src") }; URLClassLoader ul = new URLClassLoader(urls); class c = ul.loadClass("com.study.proxy.real.TankMoveProxy"); //将代理对象的委托处理类传入代理类中并生成代理类实例对象返回 Constructor cons = c.getConstructor(InvocationHandler.class); Object o = cons.newInstance(h); return o; } }
</pre><pre name="code" class="java">//客户端使用代理总类 package com.study.proxy; import java.io.IOException; import java.util.Map; import com.study.proxy.real.LogHandler; import com.study.proxy.real.Proxy; public class Client { /** * @param args */ public static void main(String[] args) { Tank tank = new Tank(); try { InvocationHandler handler=new LogHandler(tank); Imove proxyTank=(Imove)Proxy.newProxyInstance(Imove.class,handler); proxyTank.move(); } catch (Exception e) { e.printStackTrace(); } } }
执行以上代码输出:
开始时间
坦克在移动.....
结束时间
根据输出的内容,明显的动态的在坦克移动功能前后加上了其他业务处理逻辑。
其实以上Proxy类得功能就是实现动态生成代理类,这个类可以说是所有代理类的总代理。newProxyInstance方法中传入代理类实现的接口以及代理对象委托实现,通过java的反射机制拿到了实现接口的所有方法,循环遍历所有方法即可让代理对象实现接口的所有方法。这时代理类的java代码通过字符串拼接后写入到java类文件中。通过JDK自带的编译器JavaCompiler编译JAVA文件生成对应的class文件。通过类加载器加载到类存中生成对象返回给客户端。这样代理的功能就实现了,它的好处是能动态的实现接口中的所有方法。将主体核心的业务逻辑与公用的业务逻辑剥离开,比如需要计算代理对象运行了多长时间,在不改变核心业务代码的前提下就能在方法前后加上你的计算时间的代码。这段代码的功能与JDK1.6中的的代理实现机制一样,只是这里比JDK1.6中的简单一些。在spring中AOP面向切面编程也是代理的一种应用,这里的机制跟spring的机制也很像。spring生成class文件有两种生成方式
一种是JDK1.6中的编译,还有一种是cglib。cglib是不生成class文件,直接读入到类存中去。而jdk1.6的JavaCompiler是生成class编译文件,然后再通过classload加载进Jvm。
相关文章推荐
- 【练习笔记】剑指offer-输出n位数全排列
- 欢迎使用CSDN-markdown编辑器
- JDBC编程六步走
- 实习第一周总结
- 判断复选框是否被选择的方法
- Linux下SVN命令使用实例
- 好消息: 《微信商城开发实战》 已经由电子工业出版社出版发行啦
- Android TextView属性详解
- 读书笔记--TCP连接建立与终止
- leetcode之路022 Generate Parentheses
- 堆栈 (LIFO)
- 黑马程序员——TreeSet集合
- MyBatis的学习(一)
- swift学习之闭包(closure)
- unity3D java c#交互
- hadoop入门:1.hadoop简介
- 无线中继方式
- E - Swap - hdu 2819(简单二分图匹配)
- 【便签】签到app安卓客户端(开源)
- 判断密码长度