上边主要是对于静态代理的一些学习,代理送花,却赔了夫人又折兵的故事已深入人心。本篇来介绍一下何为动态代理?
动态代理,相比静态代理来说,最大的优势就是避免了重复代码的出现。上篇方法执行提示的例子,到结尾虽然我们完成了代理模式的任务,为其他对象提供一宗代理以控制对这个对象的访问,但是却远远满足不了我们的需求,如果我有多个方法,那么如果采用上述方式,我们在每个代理类的方法里都得写对应的提示,也就是重复类的代码执行影响了开发效率。
看我们之前的小例子,创建一个LogHandler,来实现创建代理类的功能:此刻我们得实现得借用反射功能来辅助完成功能。从帮助文档我们我们可以查询一下软件包java.lang.reflect,创建的类需要实现与InvocationHandler。
- InvocationHandler:是代理实例的调用处理程序实现的接口。
还需要用到一个Proxy类,实现于serializable.
- Proxy:提供用于创建动态代理和实例的静态方法,他还是由这些方法创建的所有动态代理类的超类。
动态代理,“代理角色”将不用手动生成,而是由JVM在运行时,通过指定类,接口数组,调用处理程序3个参数来动态生成。所以必须实现接口才能生成代理类。
/**
*
* @ClassName: LogHandler
* @Description: 可以创建代理的一个类,实现于InvocationHandler
* @author: HuoYaJing
* @date:2015年11月3日 上午9:56:29
*/
public class LogHandler implements InvocationHandler {
// 直接传送目标函数(也可以使用构造函数来传送)
private Object targetObject;
public Object newProxyInstance(Object targetObject) {
this.targetObject = targetObject;
// 代理加载器我们和目标加载器使用一样的/取出所有接口,会针对接口创建出一个代理类出来/this就是指当前的对象,他实现了InvocationHandler接口
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 根据选择动态变化
System.out.println("start==>" + method.getName());
for (int i = 0; i < args.length; i++) {
// args则可以根据控制参数的个数,输出传过来的参数
System.out.println(args[i]);
}
// 返回值
Object ret = null;
try {
// 调用目标方法
method.invoke(targetObject, args);
// 调用成功显示
System.out.println("success==>" + method.getName());
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
// 调用失败
System.out.println("error==>" + method.getName());
throw e;
}
return null;
}
必须调用目标接口才能对症下药创建代理类,所以我们可以直接创建一个代理类或者用构造函数来接收目标函数,如上代码。对于代理加载器调用的方法如下图:
三个参数,一个和目标函数调用的共同的加载器,一个接口列表,一个实现于InvocationHandler的处理程度,在本例中也就是本方法,所以用this来表示。
看最后的客户端调用:
public class Client {
public static void main(String[] args) {
// 创建一个对象
LogHandler logHandler = new LogHandler();
// 需要将目标传送过去,userManager为代理
UserManager userManager = (UserManager) logHandler
.newProxyInstance(new UserManagerImpl());
// 调用添加方法
userManager.addUser("0001", "huohuo");
}
}
我们这时候只需要把目标传送过去则可调用其对应的方法,不管是添加,删除,还是修改等等。因为在创建类中,args已经通过调用将参数确定了下来,看最后的效果截图:
我们调用了两个不同参数的方法,通过创建类,我们都能够实现其想要的功能。
总结:
代理模式的初衷我们必须要了解,什么时候该使用代理模式,什么时候不该使用,都要明白,比如我只需要两个方法,不涉及到代码的迭代等等,那么我们使用代理模式就多此一举,不但无优势,还因此影响了性能。
几种常用的代理方式:
- 远程代理--控制访问远程对象
- 虚拟代理--控制访问开销大的资源
- 保护代理--基于权限对资源的访问
这些都需要我们在项目中一一的去深入了解,去升华。