你的位置:首页 > Java教程

[Java教程]简单模拟java动态动态代理机制的底层实现原理


在网上学习了马士兵老师的设计模式视屏,过程中也有认真的做相应的笔记。在次分享我的一些
成果,方便大家的进一步学习。

1、接口
public interface Moveable {
    void move();
}

2、被代理的对象
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();
        }
        
    }
    
}

3、测试主类

public class Test {
    public static void main(String[] args) throws Exception{
        String rt = "\r\n";

    //代理类的字符串代码
        String src =
                "public class TankTimeProxy implements Moveable {"+rt+
                "    Moveable t;"+rt+

                "    public TankTimeProxy(Moveable t) {"+rt+
                "    this.t = t;"+rt+
                "    }"+rt+

                "    @Override"+rt+
                "    public void move() {"+rt+
                "        long start = System.currentTimeMillis();"+rt+
                "        System.out.println(\"start time is \"+start);"+rt+
                "        t.move();"+rt+
                "        long end = System.currentTimeMillis();"+rt+
                "        System.out.println(\"end time is \"+end);"+rt+
                "        System.out.println(\"time is \"+(end - start));"+rt+
                "    }"+rt+
                "}";

        //将字符串写入java文件********************************************************************************
        String fileName = System.getProperty("user.dir")+"/src/TankTimeProxy.java";//放置在(根目录+文件名)下
        File f = new File(fileName);
        FileWriter fw = new FileWriter(f);
     //写入内容
        fw.write(src);  
        fw.flush();
        fw.close();

        //进行编译********************************************************************************************
        //首先获得编译器
        //compiler 为java编译器  即javac
        //获得编译器对象
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

        //参数含义 (编译诊断,locale,charset)
        //管理动态生成的文件的StandardJavaFileManager对象
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null,null);//默认值

        //根据参数获取多个java文件   返回java文件对象集
        Iterable units = fileManager.getJavaFileObjects(fileName);

       //“编译任务”对象
        JavaCompiler.CompilationTask task = compiler.getTask(null,fileManager,null,null,null,units);
        task.call();//调用
        fileManager.close();

        //************以上过程获得了java文件源码,编译java文件生成了相对应的class文件****************

        //***************以下过程为将class文件加载至内存,生成新对象*****************************
        //Class.load() 是加载path路径的class文件
        //URLClassLoader是将硬盘中的class文件加载进入

        //通过Url引入本地文件
        URL[] urls = new URL[]{new URL("file:/"+System.getProperty("user.dir")+"/out/production/proxy")}; //访问本地class文件,这里我用的是IntellijIDEA,默认   生成的class文件的目录在  /out/production/  下


        //去指定路径寻找class文件
        URLClassLoader urlClassLoader = new URLClassLoader(urls);

        Class c = urlClassLoader.loadClass("TankTimeProxy");

        System.out.println(c);

        //执行
        //c.newInstance(); 是调用空的构造方法

        //获得构造方法
        //根据java虚拟机,每一个构造方法也相当于一个对象
        Constructor constructor = c.getConstructor(Moveable.class);

        //产生新对象
        Moveable m = (Moveable) constructor.newInstance(new Tank());  //new Tank()为构造方法的参数   即被代理对象

        m.move();

    }
}

 

4、执行结果