疯狂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 = " ";

  //代理类的字符串代码

  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();

  }

  }