最近在学习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毫秒!
汽车行驶中....
汽车结束行驶.... 汽车行驶时间:921毫秒!
最后附上项目源码下载地址!!!