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

来源:互联网 发布:淘宝上有名的女装店 编辑:程序博客网 时间:2024/05/16 19:00

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

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

import java.util.Random;/** * 需要被代理的类 * */public class Car implements Moveable {@Overridepublic 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;}/** * 实现接口方法 */@Overridepublic 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毫秒!

最后附上项目源码下载地址!!!
点击打开链接
0 0
原创粉丝点击