package com.learn.proxy;
public class Client {
public static void main(String[] args) {
Tank t = new Tank();
/**
* 对于我们client来说,我根本不知道这个方法返回给我的具体是什么类的对象
* 但是一定要求是实现这个接口的,
*/
Moveable m = (Moveable) Proxy.newProxyInstance();
m.move();
}
}
package com.learn.proxy;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.net.URLClassLoader;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
/**
* TankTimeProxy只有一个构造方法,需要传入一个Moveable对象,
* 这个动态代理我们可以往里写任何东西都可以,加入说我们生成的这个文件
* 我们用完了及把它删了,这个文件是我们动态生成的,
* 动态生成之后我们就直接把他删了,你现在根本就看不到他,你还能看到他的代理类吗
* 你就 直接newProxyInstance(),然后就可以写里面的东西了
* 就生成一个具体的代理对象了,这样我们就减少了很多具体代理类的生成
* 这就是动态的代理,你会发现我根本就不需要了解这个类叫什么名,
* 我这个类不叫TankTimeProxy,我叫做Proxy1,可以吗,
* 当然可以,JDK6是公开了Compiler API
* 原来已经有人写过这种东西了,不用JDK6你也可以使用编译命令,
* 当是这个中需要你环境上的支持,还有你可以使用SUN本身没有公开的那个类
* 也可以直接帮你生成,在这里主要介绍JDK6的新的特性
* JDK1.4就有了动态代理了,JDK1.4,1.5的机制是一样的
* 他里面也有一个Proxy的class,然后也能够产生一个新的动态代理
*
* @author Leon.Sun
*
*/
public class Test1 {
public static void main(String[] args) throws Exception {
String rt = "\r\n";
String src =
"package com.learn.proxy;" +
"public class TankTimeProxy implements Moveable {" + rt +
"public TankTimeProxy(Moveable t) {" + rt +
"super();" + rt +
"this.t = t;" + rt +
"}" + rt +
"Moveable t;" + rt +
"@Override " + rt +
"public void move() {" + rt +
"long start = System.currentTimeMillis();" + rt +
"System.out.println(\"starttime:\" + start);" + rt +
"t.move();" + rt +
"long end = System.currentTimeMillis();" + rt +
"System.out.println(\"time:\" + (end-start));" + rt +
"}" + rt +
"}";
// System.out.println(System.getProperty("user.dir"));
String fileName = System.getProperty("user.dir") + "/src/com/learn/proxy/TankTimeProxy.java";
File f = new File(fileName);
FileWriter fw = new FileWriter(f);
fw.write(src);
fw.flush();
fw.close();
/**
* compile
*/
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
// System.out.println(compiler.getClass().getName());
StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
Iterable units = fileManager.getJavaFileObjects(fileName);
CompilationTask t = compiler.getTask(null, fileManager, null, null, null, units);
t.call();
fileManager.close();
URL[] urls = new URL[] {new URL("file:/" + System.getProperty("user.dir") + "/src")};
URLClassLoader ul = new URLClassLoader(urls);
Class c = ul.loadClass("com.learn.proxy.TankTimeProxy");
System.out.println(c);
/**
* 原来我们有一个生成具体类对象的方法,这个方法叫c.newInstance()
* 但是c.newInstance()它会调用Class文件里面的参数为空的构造方法,
* 但是我们有吗,没有,这个类里面没有参数为空的构造方法,
* 那么这个时候我该怎么办呢,我这个时候可以这么办,关于Class这个类,
* 你自己去API文档里面查,它里面有一个c.getConstructor()
* getConstructor意思我可以拿到一个构造方法,
* 站在Java虚拟机的角度,每一个类,每一个Class是一个对象,这个很正常
* 每一个类里面的构造方法也算是一个对象,所以相当于Contructor ctr
* 我可以拿到其中的构造方法,我们找方法的时候是根据参数来决定的,
* 所以我们是这么来写
* 这句话什么意思,请你给我找一个构造方法,这个构造方法有一个参数,
* Moveable这种class类型,是不是我们拿到这种构造方法了
* 当我们拿到这个构造方法之后,
*/
Constructor ctr = c.getConstructor(Moveable.class);
/**
* newInstance就会产生一个新的对象,不过这个构造方法里面有一个参数
* 当然应该把参数传进去,这就是我们被代理的对象,我们找到构造方法,
* 把被代理的对象传进去,产生一个新的对象
* 这个对象我们知道他是实现Moveable接口的
*
*/
Moveable m = (Moveable) ctr.newInstance(new Tank());
/**
* 我就可以调用它的move了
*
* class com.learn.proxy.TankTimeProxy
* starttime:1556017703155
* Tank Moving.....
* time:117
*
* 到此为止我们就自己写了一个动态代理的一个类
*
*/
m.move();
}
}