模仿JDK动态代理的简单实践

最近在学习Spring以及MyBatis方面的知识,这些框架里面都会涉及到一个知识点,就是动态代理,所以作者就在慕课网上过了一遍代理模式的知识点,并对视频上的代码进行了简单的分析,加深自己对动态代理的认识。

1.首先是创建一个需要被代理的类:

import java.util.Random;

/**
 * 需要被代理的类
 *
 */
public class Car implements Moveable {

	@Override
	public void move() {
		// 实现接口方法
		try {
			Thread.sleep(new Random().nextInt(1000));
			System.out.println("汽车行驶中....");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}


2.该类实现了Moveable接口:

/**
 * 被代理类所实现的接口
 *
 */
public interface Moveable {
	void move();
}



3.接着创建一个代理实例的调用处理程序的实现类,用于加强被代理对象。

import java.lang.reflect.Method;
/**
 * 代理实例的调用处理程序的实现类,加强被代理对象
 *
 */
public class TimeHandler implements InvocationHandler {

	//被代理的对象
	private Object target;
	//构造方法接收被代理对象
	public TimeHandler(Object target) {
		super();
		this.target = target;
	}

	/**
	 * 实现接口方法
	 */
	@Override
	public void invoke(Object proxy, Method m) {
		
		try {
			long starttime = System.currentTimeMillis();
			System.out.println("汽车开始行驶....");
			m.invoke(target);
			long endtime = System.currentTimeMillis();
			System.out.println("汽车结束行驶....  汽车行驶时间:"
							+ (endtime - starttime) + "毫秒!");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}



4.该调用实现类实现了 InvocationHandler 接口:

import java.lang.reflect.Method;

/**
 * 代理实例的调用处理程序实现的接口。
 * 每个代理实例都具有一个关联的调用处理程序。
 * 对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke 方法。 
 */
public interface InvocationHandler {

	/**
	 * 在代理实例上处理方法。在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。
	 * @param proxy 在其上调用方法的代理实例。
	 * @param method 对应于在代理实例上调用的接口方法的 Method 实例。
	 * Method 对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。
	 */
	public void invoke(Object proxy,Method method);
}



5.然后创建一个代理类,该类的newProxyInstance会方法一个代理实例:

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;

import org.apache.commons.io.FileUtils;

/**
 * 动态代理类
 *
 */
public class Proxy {
	/**
	 * 返回代理类的一个实例,返回的代理类可以被当做被代理类使用(可使用被代理类在接口中声明过的方法)
	 * 
	 * @param infce
	 *            被代理类所实现接口的类类型
	 * @param h
	 *            代理实例的调用处理程序实现的接口。
	 * @return 代理类的一个实例
	 * @throws Exception
	 */
	public static Object newProxyInstance(Class infce, InvocationHandler h) throws Exception {
		// 换行符
		String rt = "\r\n";
		// 方法
		String methodStr = "";
		for (Method m : infce.getMethods()) {
			methodStr +=
					// 注解
					"	@Override" + rt +
					// 方法名
							"	public void " + m.getName() + "() {" + rt +
							// try语句
							"  try{" + rt +
							// 获取接口中的方法
							"  Method md = " + infce.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt +
							// 执行invoke方法
							"  h.invoke(this,md);" + rt +
							// catch语句块
							"  }catch(Exception e){ e.printStackTrace();}" + rt + "	}";
		}

		String str = "import java.lang.reflect.Method;" + rt + "public class $Proxy0 implements " + infce.getName()
				+ " {" + rt + "	public $Proxy0(InvocationHandler h) {" + rt + "		this.h = h;" + rt + "	}" + rt
				+ "  private InvocationHandler h;" + rt + methodStr + rt + "}";
		// 产生代理类的java文件
		String filename = System.getProperty("user.dir") + "/bin/$Proxy0.java";
		File file = new File(filename);
		FileUtils.writeStringToFile(file, str);

		// 编译
		// 拿到编译器
		JavaCompiler complier = ToolProvider.getSystemJavaCompiler();
		// 文件管理者
		StandardJavaFileManager fileMgr = complier.getStandardFileManager(null, null, null);
		// 获取文件
		Iterable units = fileMgr.getJavaFileObjects(filename);
		// 编译任务
		CompilationTask t = complier.getTask(null, fileMgr, null, null, null, units);
		// 进行编译
		t.call();
		fileMgr.close();

		// load 到内存
		ClassLoader cl = ClassLoader.getSystemClassLoader();
		Class c = cl.loadClass("$Proxy0");

		Constructor ctr = c.getConstructor(InvocationHandler.class);
		return ctr.newInstance(h);
	}

}



6.最后调用测试方法测试:

public class Client {

	/**
	 * 测试方法
	 * 
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		// 创建需要代理的对象。
		Car car = new Car();
		// 创建一个代理实例的调用处理对象。
		InvocationHandler h = new TimeHandler(car);
		// 调用代理类的静态方法,生成代理实例。
		Moveable m = (Moveable) Proxy.newProxyInstance(Moveable.class, h);
		m.move();
	}

}


所得结果如下:
汽车开始行驶....
汽车行驶中....
汽车结束行驶....  汽车行驶时间:921毫秒!

最后附上项目源码下载地址!!!
点击打开链接

你可能感兴趣的:(心得体会)