OO模式-Proxy模式借助反射实现动态代理

     上边主要是对于静态代理的一些学习,代理送花,却赔了夫人又折兵的故事已深入人心。本篇来介绍一下何为动态代理?

     动态代理,相比静态代理来说,最大的优势就是避免了重复代码的出现。上篇方法执行提示的例子,到结尾虽然我们完成了代理模式的任务,为其他对象提供一宗代理以控制对这个对象的访问,但是却远远满足不了我们的需求,如果我有多个方法,那么如果采用上述方式,我们在每个代理类的方法里都得写对应的提示,也就是重复类的代码执行影响了开发效率。

     看我们之前的小例子,创建一个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已经通过调用将参数确定了下来,看最后的效果截图:



     我们调用了两个不同参数的方法,通过创建类,我们都能够实现其想要的功能。

总结:

     代理模式的初衷我们必须要了解,什么时候该使用代理模式,什么时候不该使用,都要明白,比如我只需要两个方法,不涉及到代码的迭代等等,那么我们使用代理模式就多此一举,不但无优势,还因此影响了性能。

几种常用的代理方式:

  • 远程代理--控制访问远程对象
  • 虚拟代理--控制访问开销大的资源
  • 保护代理--基于权限对资源的访问

     这些都需要我们在项目中一一的去深入了解,去升华。


posted on 2015-11-03 21:46  huohuoL  阅读(100)  评论(0编辑  收藏  举报

导航