黑马程序员技术交流社区

标题: 第十贴 代理、概念框架图、动态代理(2) [打印本页]

作者: jinhu358    时间: 2013-5-23 17:10
标题: 第十贴 代理、概念框架图、动态代理(2)
首先编写一个生成代理主题角色的类:Proxy
  1. package com.gjy.DynamicProxy;
  2. public class Proxy {
  3.           public static Object newProxyIntenct(Class infac,InvocationHandler h) throws Exception{
  4.           String br ="\r\n";
  5.           String methString ="";
  6.           Method[] method = infac.getMethods();
  7.           for(Method m: method){
  8.                 methString = "        @Override"+ br +
  9.                                       "        public void "+m.getName()+"() {"+ br +
  10.                                       " try {" + br +
  11.                                       " Method md ="+ infac.getName()+".class.getMethod(\""+m.getName()+"\");"+ br +
  12.                                       " h.invoke(this,md);" + br +
  13.                                       " }catch (Exception e){ "+ br+
  14.                                       " e.printStackTrace();" + br +
  15.                                       " }" + br +
  16.                                       "        }";
  17.            }

  18.           String src = "package com.gjy.DynamicProxy;" + br +
  19.                    "import java.lang.reflect.Method;" + br +
  20.                    "public class $Proxy implements "+infac.getName()+"{" + br +
  21.                    "        private com.gjy.DynamicProxy.InvocationHandler h;" + br +
  22.                    "        public $Proxy(InvocationHandler h) {" + br +
  23.                    "         super();" + br +
  24.                    "         this.h = h;" + br +
  25.                    "        }" + br + br +
  26.                     methString +br +
  27.                    "}";
  28.           MakFileUtil.createFile("D:/src/com/gjy/DynamicProxy");
  29.          //生成java文件
  30.          String fileName ="D:\\src\\com\\gjy\\DynamicProxy\\$Proxy.java";
  31.          System.out.println(fileName);
  32.          File file = new File(fileName);
  33.          FileWriter fWriter = new FileWriter(file);
  34.          fWriter.write(src);
  35.          fWriter.flush();
  36.          fWriter.close();
  37.         //生成class文件,jdk6提供的工具类
  38.          JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
  39.          //System.out.println(compiler.getClass().getName());
  40.          StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
  41.          Iterable units = fileManager.getJavaFileObjects(fileName);
  42.          CompilationTask task = compiler.getTask(null, fileManager, null, null, null, units);
  43.          task.call();
  44.          fileManager.close();
  45.         //装载到内存,生成新对象
  46.          URL[] urls = new URL[]{new URL("file:/"+"D:\\src\\")};
  47.          URLClassLoader loader = new URLClassLoader(urls);
  48.          Class c = loader.loadClass("com.gjy.DynamicProxy.$Proxy");
  49.        //通过有参的构造器反射生成代理类的实例
  50.         Constructor ctr = c.getConstructor(InvocationHandler.class);
  51.          Object obj = (Object) ctr.newInstance(h);
  52.        return obj;
  53. }
  54. }
复制代码
代理对象的操作接口:
  1. package com.gjy.DynamicProxy;
  2. public interface InvocationHandler {
  3.           void invoke(Object o,Method m);
  4. }
复制代码
通过实现代理对象的操作接口实现对被代理对象的方法调用前后的逻辑操作。
TimeInvocationHandler实现InvocationHandler接口:
  1. package com.gjy.DynamicProxy;
  2. public class TimeInvocationHandler implements InvocationHandler {
  3.         private Object target;
  4.         public TimeInvocationHandler(Object target) {
  5.                   this.target = target;
  6.          }
  7.         @Override
  8.         public void invoke(Object o, Method m) {
  9.                   long time1 = System.currentTimeMillis();
  10.                   System.out.println("time1="+time1);
  11.                  try {
  12.                         m.invoke(target);
  13.                 } catch (Exception e) {
  14.                 e.printStackTrace();
  15.         }
  16.         long time2 = System.currentTimeMillis();
  17.         System.out.println("time2="+time2);
  18.         System.out.println("Tank 的启动时间:"+(time2-time1));
复制代码
实际被代理对象:Tank
  1. package com.gjy.DynamicProxy;
  2. public class Tank implements Moveable{
  3.   @Override
  4. public void move() {
  5.           int a = 5;int b = 6;int c = 0; int d = 0;
  6.           for (int i = 0; i < 1000; i++) {
  7.                 d = i;
  8.           }
  9.           c = ((a+b)/2)*12;
  10.           System.out.println("TanK moving..Tank 的速度是"+c);
  11. }
复制代码
抽象代理主题:Moveable
  1. package com.gjy.DynamicProxy;
  2.          public interface Moveable {
  3.                    void move();
  4.          }
  5. }
复制代码
测试:
  1. package com.gjy.DynamicProxy;
  2. public class TestTank {
  3.         public static void main(String[] args) throws Exception{
  4.                   Tank t = new Tank();
  5.                   Moveable moveable = (Moveable) Proxy.newProxyIntenct(Moveable.class,new TimeInvocationHandler(t));
  6.                   moveable.move();
  7.          }
  8. }
复制代码
创建文件夹工具类:MakFileUtil
  1. package com.gjy.DynamicProxy;
  2. public class MakFileUtil {
  3. public static void createFile(String pathstr) throws IOException{
  4. //创建多级目录
  5. String path = pathstr;
  6. //为指定字符串构造一个 string tokenizer。 "/"字符是分隔标记的分隔符。分隔符字符本身不作为标记。
  7. StringTokenizer st = new StringTokenizer(path,"/");
  8. String path1 = st.nextToken()+"/";
  9. String path2 = path1;
  10. while(st.hasMoreTokens())
  11. {
  12.        path1 = st.nextToken()+"/";
  13.        path2 += path1;
  14.        File inbox = new File(path2);
  15.        if(!inbox.exists())
  16.        inbox.mkdir();
  17. }
  18. }
  19. }
复制代码
以上就是动态代理的一个模拟实现,测试时我们不管Proxy和InvocationHandler是怎么实现的,我们只要实现InvocationHandler接口完成相应的逻辑,然后调用Proxy
的newProxyIntenct(Class infac, InvocationHandler h) 传入相应的接口,和InvocationHandler的实现类就可以实现对被代理对象的代理。也就是说Proxy和InvocationHandler写好之后永远不变。

在运行过程中Proxy会动态生成代理主题角色,示例中生成的代理主题角色的代码如下:
  1. public class $Proxy implements com.gjy.DynamicProxy.Moveable{
  2. private com.gjy.DynamicProxy.InvocationHandler h;
  3. public $Proxy(MakFileUtil h) {
  4.         super();
  5.         this.h = h;
  6. }
  7. @Override
  8. public void move() {
  9.         try {
  10.             Method md =com.gjy.DynamicProxy.Moveable.class.getMethod("move");
  11.             h.invoke(this,md);
  12.         }catch (Exception e){
  13.         e.printStackTrace();
  14. }
  15. }
  16. }
复制代码
如果我们想在Tank的move()方法被调用的前后加入其它的逻辑处理,我们只需实现InvocationHandler接口,下面是给move()加日志:
  1. package com.gjy.DynamicProxy;
  2. public class LogInvocationHandler implements InvocationHandler {
  3.           private Object target;
  4.           public LogInvocationHandler(Object target) {
  5.                    this.target = target;
  6.           }
  7.           @Override
  8.           public void invoke(Object o, Method m) {
  9.                   System.out.println("Tank start...........");
  10.                   try {
  11.                        m.invoke(target);
  12.                   } catch (Exception e) {
  13.                   e.printStackTrace();
  14.           }
  15.          System.out.println("Tank stop..............");
  16. }
  17. }
复制代码
测试:
  1. package com.gjy.DynamicProxy;
  2. public class TestTank {
  3.           public static void main(String[] args) throws Exception{
  4.           Tank t = new Tank();
  5.           Moveable moveable = (Moveable) Proxy.newProxyIntenct(Moveable.class,new TimeInvocationHandler(t));
  6.           Moveable moveable2 = (Moveable) Proxy.newProxyIntenct(Moveable.class, new LogInvocationHandler(moveable));
  7.           moveable2.move();
  8. }
  9. }
复制代码

作者: 袁梦希    时间: 2013-5-23 17:18
到时候帖子让老曹整理
作者: 神之梦    时间: 2013-5-23 22:08
看起来好高深啊
作者: 袁梦希    时间: 2013-5-23 22:40
神之梦 发表于 2013-5-23 22:08
看起来好高深啊

高深还来这里撸帖      你走一走游一游,就31分了 ,很啊:lol
作者: 神之梦    时间: 2013-5-23 23:29
袁梦希 发表于 2013-5-23 22:40
高深还来这里撸帖      你走一走游一游,就31分了 ,很啊

今天白天忙事去了,只有晚上撸了
作者: 袁梦希    时间: 2013-5-24 01:35
神之梦 发表于 2013-5-23 23:29
今天白天忙事去了,只有晚上撸了

苦逼




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2