其他分享
首页 > 其他分享> > 通过模拟JDK中的动态代理,由浅入深讲解动态代理思想.

通过模拟JDK中的动态代理,由浅入深讲解动态代理思想.

作者:互联网

目录

个人认为动态代理在设计模式中算是比较难的, 本篇文章将从无到有, 从一个简单代码示例开始迭代, 逐步深入讲解动态代理思想.

场景引入

class Tank implements Moveable{
    @Override
    public void move(){
        System.out.println("坦克开始移动...");
        try {
            Thread.sleep((long) (Math.random() * 5000));
            System.out.println("坦克移动结束...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

interface Moveable{
    public void move();
}
class MoveTimeProxy1 extends Tank{
    @Override
    public void move() {
        long start = System.currentTimeMillis();//开始时间
        super.move();//调用坦克的move()方法
        long end = System.currentTimeMillis();//结束时间
        System.out.println("执行该方法用了" + (end - start) + "毫秒");
    }
}
class MoveTimeProxy2 implements Moveable{
    Tank tank;

    public MoveTimeProxy2(Tank tank){
        this.tank = tank;
    }

    @Override
    public void move() {
        long start = System.currentTimeMillis();//开始时间
        tank.move();//调用坦克的move()方法
        long end = System.currentTimeMillis();//结束时间
        System.out.println("执行该方法用了" + (end - start) + "毫秒");
    }
}
public class ProxyTest {

    public static void main(String[] args) {
        TimeProxy tp = new TimeProxy(new Tank());
        LogProxy lp = new LogProxy(tp);
        lp.move();
    }
}

class TimeProxy implements Moveable{//记录时间的代理
    Moveable m;//不再持有Tank引用, 而是持有Moveable接口引用

    public TimeProxy(Moveable m){
        this.m = m;
    }

    @Override
    public void move() {
        long start = System.currentTimeMillis();//开始时间
        m.move();//调用move()方法
        long end = System.currentTimeMillis();//结束时间
        System.out.println("执行该方法用了" + (end - start) + "毫秒");
    }
}

class LogProxy implements Moveable{//打印日志的代理
    Moveable m;

    public LogProxy(Moveable m){
        this.m = m;
    }

    @Override
    public void move() {
        System.out.println("日志: 开始测试坦克移动...");
        m.move();
        System.out.println("日志: 坦克移动结束...");
    }
}

 

动态代理引入

public static void main(String[] args) {
    Tank tank = new Tank();
    Moveable m = (Moveable)Proxy.newProxyInstance();//动态获得一个代理
    m.move();
}
class Proxy{
    public static Object newProxyInstance() throws Exception {
        //把整个TimeProxy类的实现写入字符串, 通过编译这一字符串得到TimeProxy对象
        String src = "package designPattern.proxy;\n" +
                "\n" +
                "class TimeProxy implements Moveable{\n" +
                "    Moveable m;//不再持有Tank引用, 而是持有Moveable接口引用\n" +
                "\n" +
                "    public TimeProxy(Moveable m){\n" +
                "        this.m = m;\n" +
                "    }\n" +
                "\n" +
                "    @Override\n" +
                "    public void move() {\n" +
                "        long start = System.currentTimeMillis();//开始时间\n" +
                "        m.move();//调用坦克的move()方法\n" +
                "        long end = System.currentTimeMillis();//结束时间\n" +
                "        System.out.println(\"执行该方法用了\" + (end - start) + \"毫秒\");\n" +
                "    }\n" +
                "}";
        String filename = System.getProperty("user.dir")
                + "/src/main/java/designPattern/proxy/TimeProxy.java";//文件名(生成类的路径)
        File f = new File(filename);
        FileWriter fw = new FileWriter(f);
        fw.write(src);
        fw.flush();
        fw.close();

        //编译
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();//拿到系统当前默认的编译器, 即Javac
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
        Iterable units = fileManager.getJavaFileObjects(filename);//得到文件对象
        JavaCompiler.CompilationTask t = compiler.getTask(null, fileManager, null, null, null, units);
        t.call();//进行编译
        fileManager.close();

        //把class文件加载进内存并创建对象
        URL[] urls = new URL[]{new URL("file:/" + System.getProperty("user.dir") + "/src")};
        URLClassLoader ul = new URLClassLoader(urls);
        Class c = ul.loadClass("designPattern.proxy.TimeProxy");//拿到class对象

        Constructor ctr = c.getConstructor(Moveable.class);//拿到参数为Moveable的构造方法
        Moveable m = (Moveable)ctr.newInstance(new Tank());//创建代理对象
        return m;
    }
}
public class ProxyTest {

    public static void main(String[] args) throws Exception {
        Tank tank = new Tank();
        Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class);//传入接口参数动态获得一个代理
        m.move();
    }
}

class Proxy{
    public static Object newProxyInstance(Class intfce) throws Exception {
        //把整个TimeProxy类的实现写入字符串, 通过编译这一字符串得到TimeProxy对象
        String methodStr = "";
        String n = "\n";

        Method[] methods = intfce.getMethods();//拿到接口中的所有方法
        for(Method m : methods){//拼接方法
            methodStr += "    @Override\n" +
                    "    public void " + m.getName() + "() {\n" +
                    "        long start = System.currentTimeMillis();//开始时间\n" +
                    "        m.move();//调用坦克的move()方法\n" +
                    "        long end = System.currentTimeMillis();//结束时间\n" +
                    "        System.out.println(\"执行该方法用了\" + (end - start) + \"毫秒\");\n" +
                    "    }\n";
        }
        //拼接出整个类
        String src = "package designPattern.proxy;\n" +
                "\n" +
                "class TimeProxy implements " + intfce.getName() + "{\n" +
                "    Moveable m;//不再持有Tank引用, 而是持有Moveable接口引用\n" +
                "\n" +
                "    public TimeProxy(Moveable m){\n" +
                "        this.m = m;\n" +
                "    }\n" +
                "\n" + methodStr +
                "}";

        String filename = System.getProperty("user.dir")
                + "/src/main/java/designPattern/proxy/TimeProxy.java";//文件名(生成类的路径)
        File f = new File(filename);
        FileWriter fw = new FileWriter(f);
        fw.write(src);
        fw.flush();
        fw.close();

        //编译
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();//拿到系统当前默认的编译器, 即Javac
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
        Iterable units = fileManager.getJavaFileObjects(filename);//得到文件对象
        JavaCompiler.CompilationTask t = compiler.getTask(null, fileManager, null, null, null, units);
        t.call();//进行编译
        fileManager.close();

        //把class文件加载进内存并创建对象
        URL[] urls = new URL[]{new URL("file:/" + System.getProperty("user.dir") + "/src")};
        URLClassLoader ul = new URLClassLoader(urls);
        Class c = ul.loadClass("designPattern.proxy.TimeProxy");//拿到class对象

        Constructor ctr = c.getConstructor(Moveable.class);//拿到参数为Moveable的构造方法
        Object m = ctr.newInstance(new Tank());//创建代理对象
        return m;
    }
}

 

动态代理进阶

public class ProxyTest {

    public static void main(String[] args) throws Exception {
        Tank tank = new Tank();
        InvocationHandler h = new TimeHandler(tank);
        Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class, h);//动态获得一个代理
        m.move();
    }
}

interface InvocationHandler{
    public void invoke(Object o, Method m);//参数o指定执行对象(代理对象, 可能会用到), m指定执行的方法
}

class TimeHandler implements InvocationHandler{
    private Object target;

    public TimeHandler(Object target){
        this.target = target;
    }

    @Override
    public void invoke(Object o, Method m) {
        long start = System.currentTimeMillis();//这行是用户自己加的增强代码
        try{
            m.invoke(target);
        } catch (Exception e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();//这行是用户自己加的增强代码
        System.out.println("执行该方法用了" + (end - start) + "毫秒");//这行是用户自己加的增强代码
    }
}

class Proxy{
    public static Object newProxyInstance(Class intfce, InvocationHandler h) throws Exception {
        //把整个TimeProxy类的实现写入字符串, 通过编译这一字符串得到TimeProxy对象
        String methodStr = "";

        Method[] methods = intfce.getMethods();//拿到接口中的所有方法
        for(Method m : methods){//拼接方法
            methodStr += "    @Override\n" +
                    "    public void " + m.getName() + "() {\n" +
                    "        try{\n" +
                    "        Method md = " + intfce.getName() + ".class.getMethod(\"" + m.getName() + "\");\n" +
                    "        h.invoke(this, md);\n" +
                    "        }catch(Exception e){e.printStackTrace();}\n" +
                    "    }\n";
        }
        //拼接出整个类
        String src = "package designPattern.proxy;\n" +
                "import java.lang.reflect.Method;\n" +
                "\n" +
                "class $Proxy1 implements " + intfce.getName() + "{\n" +
                "    designPattern.proxy.InvocationHandler h;\n" +
                "\n" +
                "    public $Proxy1(InvocationHandler h){\n" +
                "        this.h = h;\n" +
                "    }\n" +
                "\n" + methodStr +
                "}";

        String filename = System.getProperty("user.dir")
                + "/src/main/java/designPattern/proxy/$Proxy1.java";//文件名(生成类的路径)
        File f = new File(filename);
        FileWriter fw = new FileWriter(f);
        fw.write(src);
        fw.flush();
        fw.close();

        //编译
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();//拿到系统当前默认的编译器, 即Javac
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
        Iterable units = fileManager.getJavaFileObjects(filename);//得到文件对象
        JavaCompiler.CompilationTask t = compiler.getTask(null, fileManager, null, null, null, units);
        t.call();//进行编译
        fileManager.close();

        //把class文件加载进内存并创建对象
        URL[] urls = new URL[]{new URL("file:/" + System.getProperty("user.dir") + "/src")};
        URLClassLoader ul = new URLClassLoader(urls);
        Class c = ul.loadClass("designPattern.proxy.$Proxy1");//拿到class对象

        Constructor ctr = c.getConstructor(InvocationHandler.class);//拿到参数为Moveable的构造方法
        Object m = ctr.newInstance(h);//创建代理对象
        return m;
    }
}

class Tank implements Moveable{
    @Override
    public void move(){
        System.out.println("坦克开始移动...");
        try {
            Thread.sleep((long) (Math.random() * 5000));
            System.out.println("坦克移动结束...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

//输出结果
坦克开始移动...
坦克移动结束...
执行该方法用了4302毫秒

 

总结

public void invoke(Object o, Method m) {
    long start = System.currentTimeMillis();//这行是用户自己加的增强代码
    try{
        m.invoke(target);//执行被增强的方法, 例子中的move()
    } catch (Exception e) {
        e.printStackTrace();
    }
    long end = System.currentTimeMillis();//这行是用户自己加的增强代码
    System.out.println("执行该方法用了" + (end - start) + "毫秒");//这行是用户自己加的增强代码
}

 

class $Proxy1 implements designPattern.proxy.Moveable{
    designPattern.proxy.InvocationHandler h;

    public $Proxy1(InvocationHandler h){
        this.h = h;
    }

    @Override
    public void move() {
        try{
            Method md = designPattern.proxy.Moveable.class.getMethod("move");
            h.invoke(this, md);
        }catch(Exception e){e.printStackTrace();}
    }
}
watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

 

  1. 对于任意一个实现了某个接口的类, 我们都可以对其实现的接口中定义的方法进行增强.
  2. 可以在被增强方法前后自定义增强的逻辑.
  3. 可以进行多层嵌套代理.

标签:JDK,class,move,System,代理,Moveable,动态,public
来源: https://blog.51cto.com/u_14797091/2758950