设计模式之_动态代理_05

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

猜你喜欢

转载自blog.csdn.net/Leon_Jinhai_Sun/article/details/89479126