设计模式之代理模式一
现在只是对小汽车进行代理,如果要实现对火车,自行车的代理是不是需要创建火车代理类,自行车代理类等,太麻烦了。可以通过动态代理进行实现。
JDK动态代理
创建一个TimeHandler的时间处理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* Create by fengguofei
* Date: 2018/8/5
* Time: 15:16
*/
public class TimeHandler implements InvocationHandler {
private Object target;
public TimeHandler(Object target) {
super();
this.target = target;
}
/**
* @param proxy 被代理对象
* @param method 被代理对象的方法
* @param args 方法的参数
* @return 方法的返回值
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long starttime = System.currentTimeMillis();
System.out.println("汽车开始行驶。。。");
method.invoke(target);
long endtime = System.currentTimeMillis();
System.out.println("汽车结束行驶。。。 汽车行驶时间:" + (endtime - starttime) + "毫秒!");;
return null;
}
}
创建Test测试类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
* Create by fengguofei
* Date: 2018/8/5
* Time: 15:21
*/
public class Test {
/**
* jdk动态代理测试
* @param args
*/
public static void main(String[] args) {
Car car = new Car();
InvocationHandler h = new TimeHandler(car);
Class> cls = car.getClass();
/**
* loader 类加载器
* interfaces 实现接口
* h InvocationHandler
*/
Moveable m = (Moveable) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), h);
m.move();
}
}
输出
汽车开始行驶。。。
汽车行驶中。。。
汽车结束行驶。。。 汽车行驶时间:607毫秒!
所谓Dynamic Proxy是这样一种class:
它是在运行时生成的clas
该class需要实现一组interface
使用动态代理类时,必须实现InvocationHandler接口
动态代理类实现步骤:
1 创建一个实现接口InvocationHandler的类,它必须实现invoke方法
2 创建被代理的类以及接口
3 调用Proxy的静态方法,创建一个代理类 newProxyInstance(ClassLoader loader,Class[] interfaces, InvocationHandler h)
4 通过代理调用方法
cglib动态代理
JDK动态代理 | CGLIB动态代理 |
---|---|
只能代理实现了接口的类 | 针对类来实现代理的 |
没有实现接口的类不能实现JDK的动态代理 | 对指定目标类产生一个子类,通过方法拦截技术拦截所有父类方法的调用 |
创建Train类
public class Train {
public void move(){
System.out.println("火车行驶中。。。");
}
}
创建CglibProxy类
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* Create by fengguofei
* Date: 2018/8/5
* Time: 18:06
*/
public class CglibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz){
//设置创建子类的类
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
/**
* 拦截所有目标类方法的调用
* @param o 目标类的实例
* @param method 目标方法的反射对象
* @param objects 方法的参数
* @param methodProxy 代理类的实例
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("日志开始。。。");
//代理类调用父类的方法
methodProxy.invokeSuper(o, objects);
System.out.println("日志结束。。。");
return null;
}
}
创建测试类
public class Client {
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
Train t = (Train)proxy.getProxy(Train.class);
t.move();
}
}
输出
日志开始。。。
火车行驶中。。。
日志结束。。。
JDK动态代理模拟
动态代理实现思路:
实现功能:通过Proxy的newProxyInstance返回代理对象
1 声明一段源码(动态产生代理)
2 编译源码(JDK Compiler API),产生新的类(代理类)
3 将这个类load到内存当中,产生一个新的对象(代理对象)
4 return 代理对象
创建Proxy类
package pattern.proxy.simulateProxy;
import org.apache.commons.io.FileUtils;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import javax.tools.JavaCompiler.CompilationTask;
/**
* Create by fengguofei
* Date: 2018/8/5
* Time: 19:55
*/
public class Proxy {
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{" + rt +
" Method md = " + infce.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt +
" h.invoke(this, md);" + rt +
" }catch(Exception e){e.printStackTrace();}" + rt +
" }";
}
String str =
"package pattern.proxy.simulateProxy;" + rt +
"import pattern.proxy.simulateProxy.InvocationHandler;" + rt +
"import java.lang.reflect.Method;" + rt +
"public class $Proxy0 implements " + infce.getName() + " {" + rt +
" public $Proxy0(InvocationHandler h) {" + rt +
" super();" + rt +
" this.h = h;" + rt +
" }" + rt +
" private InvocationHandler h;" + rt +
methodStr + rt +
"}";
//产生代理类的java文件
String filename = System.getProperty("user.dir") + "\\bin\\pattern\\proxy\\simulateProxy\\$Proxy0.java";
System.out.println(filename);
File file = new File(filename);
FileUtils.writeStringToFile(file, str);
//编译
//拿到编译器
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
//文件管理者
StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
//获取文件
Iterable units = fileMgr.getJavaFileObjects(filename);
List options = new ArrayList();
options.add("-encoding");
options.add("UTF-8");
//编译任务
CompilationTask t = compiler.getTask(null, fileMgr, null, options, null, units);
//进行编译
t.call();
fileMgr.close();
//load到内存中
// ClassLoader cl = ClassLoader.getSystemClassLoader();
// System.out.println(cl.toString());//sun.misc.Launcher$AppClassLoader@18b4aac2
DiskClassLoader diskLoader = new DiskClassLoader(System.getProperty("user.dir") + "\\bin\\pattern\\proxy\\simulateProxy");
Class c = diskLoader.loadClass("pattern.proxy.simulateProxy.$Proxy0");
System.out.println(c.getName());
Constructor ctr = c.getConstructor(InvocationHandler.class);
return ctr.newInstance(h);
}
}
主要代码是Proxy的创建,建议看一下慕课上面的课程,很清晰,主要是字符串的拼接,编译,加载到内存,然后是创建代理类实例。但是在编写代码的时候一模一样就是不能运行,一直报错,无法把编译后的$Proxy0.class加载到内存中,可能是jdk版本或者其他问题。后来参考一看你就懂,超详细java中的ClassLoader详解创建了DiskClassLoader类加载器,就可以加载到内存了。其他的代码就参考github,不在粘贴了。
全部演示代码在github