java学习之路----静态代理---动态代理-----AOP的前奏(AOP也是动态代理)(二)

2014-11-24 08:09:46 · 作者: · 浏览: 5
public class Client { public static void main(String[] args) { Tank t= new Tank(); TankTimeProxy time= new TankTimeProxy(t); TankLogProxy log= new TankLogProxy(time); Moveable m=log; m.move(); }
}
结果:
Tank start Tank moving.... 484 Tank end
是不是很方便的就修改了我们的代码

这上面的就可以叫静态代理

4.现在有出现了一个问题?如果我现在有多个类,那我是不是要去实现多个计时,多个日志,那不是和刚才的继承一样,造成了类的大量产生(重复),这样显然是不合理的,那我们带怎么办喃? 我们现在就可以使用动态代理

我们来自己写一个动态代理类,名字叫Proxy
源码:
public class Proxy { //这个类的作用就是用来产生新的代理类 public static Object newProxyInstance(){ /*把这个类当成一个string的字符串(源码) 现在我们假设,我们能把这字符串编译,生成类,放在内存,来产生对象 动态代理就是你看不到代理类,你只需要调用一个方法( Proxy的newProxyInstance()方法), 会自动给你返回一个代理类对象,这个对象的产生是由内部动态的生成一段代码,编译完成的*/ String src= "package com.text;"+
"public class TankTimeProxy implements Moveable{"+ "public TankTestProxy(Moveable t) {" + " this.t = t;" + " }"+ " Moveable t;" + " @Override" + " public void move() {" + " long start=System.currentTimeMillis();"+ " t.move();" + " long end=System.currentTimeMillis();" + " System.out.println((end-start));" + " }"+ "}"; return null ; }
} 上面的注释解释的很清楚了。。
现在我们就来动态的编译这段代码
一般动态编译文件有这些方法(用JDK6的complier API(大于1.6都行,只是这个是1.6的新特性),CGlib,ASM(直接生成二进制的class文件))
我们直接用JDK的 complier

我们要做的步骤:
把字符串进行编译 生成一个类 写入内存 生成对象 下面我们就来一一实现
我们先写一个测试类,叫Test1.java
源码:
第一步:
public class Test1 { public static void main(String[] args) throws Exception { //来测试怎么编译这段代码 String src= "package com.text;"+
"public class TankTimeProxy implements Moveable{"+ "public TankTimeProxy(Moveable t) {"+ " this.t = t;" + " }"+ " Moveable t;" + " @Override" + " public void move() {" + " long start=System.currentTimeMillis();"+ " t.move();" + " long end=System.currentTimeMillis();"+ " System.out.println((end-start));" + " }"+ "}"; //获取当前系统目录(就是项目根目录) String fileName=System. getProperty("user.dir") ; System.out.println(fileName);//先输出我们获取的根目录 } }
第二步: 我们输出了根目录之后,我们就来编译这段字符串
修改 String fileName=System. getProperty( "user.dir" )+"/src/com/text/TankTimeProxy.java"; 这样做的目的是为了让生成的代码就在我们的项目的文件里
添加以下代码:
File f= new File(fileName); FileWriter writer= new FileWriter(f); writer.write(src); writer.flush(); writer.close();
在做这一步之前,如果你的文件里有TankTimeProxy.java文件,你把它删除了,不需要了,因为我可以动态的来生成了。 运行代码,完成之后,右键项目,刷新,你会看到出现了一个TankTimeProxy.java文件.OK,第二步完成
第三步: 我们来生成一个类
//这句话的作用就是获取系统当前默认的编译器(其实就 javacJavaCompiler compiler=ToolProvider. getSystemJavaCompiler(); //拿到java的编译器 System. out.println(compiler.getClass().getName()); StandardJavaFileManager filemag=compiler.getStandardFileManager( null, null, null);//文件的 管理器 Iterable untis= filemag.getJavaFileObjects(fileName);//找到文件,把文件放在 Iterable(数组)中 CompilationTask t=compiler.getTask( null, filemag, null, null , null, untis );//定好编译文件任务 t.call(); //编译文件 filemag.close();//关闭文件管理器
运行:
编译之后,我们打开window show View 选择Navigator(这个可以看到类详细的变化,就是看得到class文件的产生) 就会看到多了一个TankTimeProxy.class 文件,第三步成功

第四步:
我们把文件加入内存(原本一般的做法是class.loader,就OK了,但是调用这个方法的前提就是,你的class文件目录必须在classpath的文件目录下),我们这里用一种通用的做法 //这里使用url加载器 URL [] urls= new URL[]{ new URL("file:/"+System. getProperty( "user.dir")+"/src" )}; URLClassLoader ul= new URLClassLoader(urls);//这里需要一个数组地址 Class c=ul.loadClass("com.text.TankTimeProxy" );//把类加到内存 System. out.println(c);
测试:输出c,OK,第四步完成
最后一步,生成对象
//反射来创建对象 Constructor ctr= c.getConstructor(Moveable. class ) ;//获取构造方法 Moveable