zoukankan      html  css  js  c++  java
  • 学习:java设计模式—动态代理模式

    类定义:

    1、被代理接口和实现类:Tank类实现了Moveable接口,能够move()

    package com.zec.disignmode;
    public interface Moveable {
        public void move();
    }

    package com.zec.disignmode;
    import java.util.Random;
    public class Tank implements Moveable{
        @Override
        public void move() {
            System.out.println("Tank moving....");
            try {
                Thread.sleep(new Random().nextInt(10000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    2、代理加工接口和实现类:TimeHandler类实现了InvocationHandler接口,能够invoke(Object object,Method m)在object的m方法前后加上自己记录时间的逻辑,并不是代理类,只是提供了对被代理类的加工逻辑;

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

    package com.zec.disignmode;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    public class TimeHandler implements InvocationHandler{
        @Override
        public void invoke(Object object, Method m) {
            System.out.println("Time Before "+m.getName());
            try {
                m.invoke(object);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("Time After  "+m.getName());
        }

    }

    3、生成动态代理类的Proxy静态类:代理产生器,根据传进来的参数Class Intface和InvocationHandler h,产生动态代理类;从而使intface中的所有方法都加上了h中invoke方法的自定义逻辑;为了便于代理类的组合和扩展,代理类也会实现Intface接口,最终返回一个代理类对象;

    package com.zec.disignmode;
    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.StandardJavaFileManager;
    import javax.tools.ToolProvider;
    import javax.tools.JavaCompiler.CompilationTask;
    public class Proxy {
        public static Object newInstance(Class intface,InvocationHandler h) throws Exception {
            /*Generate the source code*/
            String rt = "\r\n";
            String methodStr = "";
            for (Method method:intface.getMethods()) {
                methodStr +=
                "    @Override"+rt+
                "    public void "+ method.getName() +"() {"+rt+
                "        try{"+rt+
                "            Method m = "+ intface.getName()+".class.getMethod(\""+ method.getName() +"\");" + rt+
                "            h.invoke(tank,m);"+rt+
                "        }catch(Exception e){e.printStackTrace();}"+rt+
                "    }"+rt
                ;
            }
            String src =
                "package com.zec.disignmode;"+rt+
                "import java.util.Random;"+rt+
                "import java.lang.reflect.*;"+rt+
                "public class TankTimeProxy implements "+ intface.getName() +"{"+rt+
                "    "+ intface.getName() +" tank;"+rt+
                "    com.zec.disignmode.InvocationHandler h;"+rt+
                "    public TankTimeProxy("+ intface.getName() +" t,com.zec.disignmode.InvocationHandler h) {"+rt+
                "        tank = t;"+rt+
                "        this.h = h;"+rt+
                "    }"+rt+
                methodStr+
                "}";
            /*Generate the java file*/
            String fileName = System.getProperty("user.dir")+"/src/com/zec/disignmode/TankTimeProxy.java";
            File f = new File(fileName);
            FileWriter fw = new FileWriter(f);
            fw.write(src);
            fw.flush();
            fw.close();
            /*Generate the class file*/
            JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager jfMgr = jc.getStandardFileManager(null, null, null);
            Iterable units = jfMgr.getJavaFileObjects(fileName);
            CompilationTask ct =  jc.getTask(null, jfMgr, null, null, null, units);
            ct.call();
            jfMgr.close();
            /*Load the class into the memory*/
            URL[] urls = new URL[]{new URL("file:/"+System.getProperty("user.dir")+"/src")};
            URLClassLoader urlLoader = new URLClassLoader(urls);
            Class c = urlLoader.loadClass("com.zec.disignmode.TankTimeProxy");
            /*Generate the object*/
            Constructor constructor = c.getConstructor(Moveable.class,InvocationHandler.class);
            Object moveable = constructor.newInstance(new Tank(),h);
            return moveable;
        }
    }

    4、测试类

    package com.zec.disignmode;
    public class Client {
        public static void main(String[] args) {
            Moveable m = new Tank();
            LogHandler h = new LogHandler();
            try {
                Moveable moveable = (Moveable) Proxy.newInstance(Moveable.class, h);
                moveable.move();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    5、学习心得:

    (1)为了增强代理类的可扩展性,代理类和被代理类实现的是同一个接口,这样代理类可以作为被代理类再次被代理,可以实现不同功能代理的组合,本例中为Moveable;

    (2)InvocationHandler接口定义了对特定对象的方法的代理加工方法,Proxy为代理生成器,newInstance(Class intface,InvocationHandler h)方法表示对intface接口的所有方法进行加工,加工的逻辑由h的invoke方法定义;

    (3)代理生成器最后返回一个intface类型的引用,指向已经生成的动态代理类;

    (4)对于使用者来说,不必关心动态代理类的名称,只需要指定要代理的接口类型和处理类就可以了。

  • 相关阅读:
    KlayGE 4.0功能规划
    Kinect for Windows SDK发布
    CENTOS下用syslogng集中管理日志并压缩保存
    Eclipse+Plugin
    struts2 获取request、session的方法
    ActiveMQ使用经验
    springmock + dbutil 用来测试数据库操作
    英语学习
    如何查看eclipse版本
    jQuery插件的开发
  • 原文地址:https://www.cnblogs.com/forlina/p/2085831.html
Copyright © 2011-2022 走看看