使用自动生成java文件和自动编译的动态代理模式-马士兵设计模式教程

/*
 * 接口中有几个方法,那么使用反射的getMethods()就会有几个方法名
 * 因为接口是不会继承Object的
 */
public interface Moveable {
	void move();//
}

public class Car implements Moveable{
	@Override
	public void move() {
		System.out.println("我是卡车,出发开往目的地...");
	}
}

public interface UserMgr {
	void addUser();
}

public class UserMgrImpl implements UserMgr {
	@Override
	public void addUser() {
		System.out.println("1: 插入记录到user表");
		System.out.println("2: 做日志在另外一张表");
	}
}

//作为动态代理的预设框架,把需要增加的内容放入事先写好的功能中
public interface InvocationHandler {
	/**
	 * @param obj 要代理类的对象car
	 * @param method 要代理类的对象car的代理方法
	 */
	void invoke(Object obj,Method method);
}

//对要代理类的对象的方法进行运行时间长短的测量
public class TimerInvocation implements InvocationHandler{
	//target是要代理的对象,在客户端创建TimeInvocation时就进行传递
	//为什么不在下面的invoke里直接传递obj为要代理的对象呢?
	//那是因为在Proxy1类中要创建一个临时的代理对象$Proxy,然后这个$Proxy
	//的对象会会调用这个TimerInvocation中的invoke方法,这个时候无法传递真
	//正的要代理的对象,使用反射也不行,因为反射只会创建一个新的实例,而非一
	//个拥有某种属性或功能的对象,故只能在客户端中进行传递
	private Object target;
	
	public TimerInvocation(Object target){
		this.target=target;
	}
	
	//method是要代理的对象的方法
	//这里的obj暂时没起到作用
	@Override
	public void invoke(Object obj, Method method) {
		System.out.println("开始进行运行时间测量...");
		long start=System.currentTimeMillis();
		try {
			method.invoke(target);
		} catch (Exception e) {
			e.printStackTrace();
		} 
		System.out.println("共耗费时间:"+(System.currentTimeMillis()-start));
	}

}

public class TransactionHandler implements InvocationHandler {
	
	private Object target;
	
	public TransactionHandler(Object target) {
		super();
		this.target = target;
	}

	@Override
	public void invoke(Object o, Method m) {
		System.out.println("Transaction Start");
		try {
			m.invoke(target);
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("Transaction Commit");
	}

}

public class Proxy1 {
	/**
	 * 
	 * @param interfa 这个就是Moveable接口的class
	 * @param h 告诉Proxy类要产生的是什么类型的代理,可以是时间代理,日志代理
	 * 也就是要对interfa里的方法实现什么样的代理或功能
	 * @return
	 * 思路:
	 * 生成一个临时的代理类$Proxy,这个类继承于Moveable接口
	 * 这个类要去调用InvacationHandler的子类的invoke方法,实现切面的功能
	 * 然后返回这个临时代理类的对象,并让得到这个代理类的对象调用move()方法即可
	 */
	public static Object newProxyInstance(Class interfa,InvocationHandler h)throws Exception{
		String rt="\r\n";
		String java="package proxy1.dynamic;" +  rt ;
			  java+="import java.lang.reflect.Method;" + rt ;
			  java+="public class $Proxy implements "+interfa.getName() +"{" + rt;
			  java+="	private InvocationHandler hand;" + rt;
			  java+="	public $Proxy(InvocationHandler hand){" + rt;
			  java+="		this.hand=hand;" + rt;
			  java+="	}" + rt;
			  
			  Method[] methods=interfa.getMethods();
			  for(Method method : methods){//对接口interfa中的方法进行实现
				  java+="	@Override" + rt;
				  java+="	public void "+method.getName()+"(){" + rt;
				  java+="		try{" + rt;				  
					  java+="		Method m="+interfa.getName()+".class.getMethod(\""+method.getName()+"\");" + rt;
					  java+="		hand.invoke(this,m);" + rt;
					  java+="	}catch(Exception e){e.printStackTrace();}" + rt;		
				  java+="	}" + rt;
			  }
			  java+="}" + rt;
			  System.out.println(java);
		//创建java文件
		  String filepath=System.getProperty("user.dir")+"/src/proxy1/dynamic";
		  File file=new File(filepath+"/$Proxy.java");
		  try{
			file.createNewFile();
			FileWriter fw=new FileWriter(file);
			fw.write(java);
			fw.close();	
		  }catch(Exception e){e.printStackTrace();}
		//编译
			JavaCompiler javac=ToolProvider.getSystemJavaCompiler();
			StandardJavaFileManager javafile=javac.getStandardFileManager(null, null, null);
			String filename=filepath+"/$Proxy.java";
			Iterable units=javafile.getJavaFileObjects(filename);
			CompilationTask t=javac.getTask(null, javafile, null, null, null, units);
			t.call();
			try {javafile.close();
			} catch (IOException e) {e.printStackTrace();}
		//把刚才在D:/下生成的class文件CarTimeProxy.class加载进内存并生成实例对象
		URL[] urls;
		Object obj=null;
		try {
			urls = new URL[]{new URL("file:///D:/Workspaces/base/bin/")};
			URLClassLoader classload=new URLClassLoader(urls);
			Class clazz=classload.loadClass("proxy1.dynamic.$Proxy");
			Constructor cons=clazz.getConstructor(InvocationHandler.class);
			obj=cons.newInstance(h);
		} catch (Exception e) {
			e.printStackTrace();
		} 
		return obj;
		
	}
}

public class Client {
	public static void main(String[] args) throws Exception {
		
		/*Moveable move=new Car();
		Moveable proxy=(Moveable) Proxy.newProxyInstance(move);
		proxy.move();*/
		/*Moveable move=new Car();
		InvocationHandler hand=new TimerInvocation(move);
		Moveable proxy=(Moveable)Proxy1.newProxyInstance(Moveable.class, hand);
		proxy.move();*/
		UserMgr mgr = new UserMgrImpl();
		InvocationHandler h = new TransactionHandler(mgr);//先对日志进行捕获
		UserMgr u = (UserMgr)Proxy1.newProxyInstance(UserMgr.class,h);
		InvocationHandler h2 = new TimerInvocation(u);//再对时间进行测量
		UserMgr u1 = (UserMgr)Proxy1.newProxyInstance(UserMgr.class,h2);
		u1.addUser();
		/**
		 * 运行结果:
		 * 开始进行运行时间测量...
		 * Transaction Start
		 * 1: 插入记录到user表
		 * 2: 做日志在另外一张表
		 * Transaction Commit
		 * 共耗费时间:0
		 */
	}
}

本文转自: http://blog.csdn.net/wxwzy738/article/details/7703990

你可能感兴趣的:(使用自动生成java文件和自动编译的动态代理模式-马士兵设计模式教程)