代理模式ProxyPattern以及java对此的支持——动态代理

本文详细介绍了Java中的代理模式,包括静态代理和动态代理的概念、原理及实现方式。通过定制西服的例子,生动形象地展示了代理模式的应用场景。此外,还提供了完整的代码示例,帮助读者更好地理解和掌握这一设计模式。

代理模式,即Proxy Pattern,23种java常用设计模式之一。代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。通俗的说,就是客户端通过代理对象去操纵委托对象(或者说被代理对象)。

举个例子,就业季到了,你需要定制一套西服,打扮一番,人模人样偷笑给面试官留个好印象。通常校园里贴小广告为同学定制西服的并不是裁缝铺而是中介或者说是裁缝铺的代理,按照小广告上留的地址你找到了这家高端大气上档次西服代理,“请问您有什么需求?“代理满脸欢喜,这时你就会洋气地告诉代理:我想要一套高大上的西服,速速给爷做好,钱不是问题~~奋斗代理爽快答应,量了身材尺寸并让你预交一定量定金后就让你回去了,”帅哥,三天之后来取,包您满意!得意“。然后代理会转告幕后的裁缝铺:做一套高大上的西服,尺寸在这,三天交货,速度!裁缝铺接到这单业务便会连夜赶制,三天后交到代理那里。代理约你到店里,交付衣服,收取货款。至此,代理模式就完成了,裁缝铺拥有做西服的能力,但它并不直接与客户打交道,而是委托代理接洽生意。通过代理,客户不仅可以间接让裁缝铺做西服还可以在代理那里做一些其他的事情,比如谈价格、交定金、试衣服、交货款等等(我们假设裁缝铺没有这些能力,比如裁缝是个哑巴尴尬不会讲话没法跟你谈价格)。

下面我们用代码实现代理模式:

代理模式中,委托类和代理类实现同一个接口,取名叫Seller:

package proxypattern;

//代理模式中委托类和代理类统一实现的接口
public interface Seller {
	// 接口函数:做一套西服
	public void workOnSuite();
}
委托类——裁缝类Tailor,实现Seller接口:
package proxypattern;

public class Tailor implements Seller {

	@Override
	public void workOnSuite() {
		// TODO Auto-generated method stub
		System.out.println("我是裁缝,我正在做一套西服。");
	}

}
代理类Agency,同样实现Seller接口:

package proxypattern;

public class Agency implements Seller {

	private Tailor tailor; // 中介持有裁缝对象的引用,通过此引用让裁缝做西服

	public Agency(Tailor tailor) {
		this.tailor = tailor;
	}

	@Override
	public void workOnSuite() {
		// TODO Auto-generated method stub
		System.out.println("我是中介,我让裁缝做西服。");

		doSomethingBefore();

		tailor.workOnSuite();

		doSomethingAfter();
	}

	private void doSomethingAfter() {
		// TODO Auto-generated method stub
		System.out.println("在给客户西服前,让他试试合身不,把没交的钱补齐");
	}

	private void doSomethingBefore() {
		// TODO Auto-generated method stub
		System.out.println("在让裁缝做西服前,谈价格、量尺寸、交定金");
	}

}

下面通过客户端完成对代理模式的完整测试:

package proxypattern;

public class Test {

	public static void main(String[] args) {
		Tailor tailor = new Tailor(); // 裁缝对象
		Agency agency = new Agency(tailor); // 代理对象

		agency.workOnSuite(); // 让代理做一套西服,代理会在内部让裁缝做西服
	}

}
输出:

我是中介,我让裁缝做西服。
在让裁缝做西服前,谈价格、量尺寸、交定金
我是裁缝,我正在做一套西服。
在给客户西服前,让他试试合身不,把没交的钱补齐

可以看到,通过代理模式,用户不仅可以让委托类完成工作外,还可以在代理类中做一些委托类不能完成的任务,这就是Java Web编程中拦截器的概念~面向切面编程AOP。

并且代理和委托类实现同一个接口,让他们具有相同的 对外接口~

上面这种代理模式叫做静态代理模式,java提供了对代理模式的更高级支持——动态代理模式

动态代理模式主要涉及到java.lang.reflect包中的Proxy静态类以及InvocationHandler接口,具体用法请参考API文档。

动态代理是很多框架和技术的基础,Spring的AOP实现就是基于动态代理的。了解动态代理的机制对于理解AOP的底层实现很有帮助。

Proxy静态类用于创建代理类,这个代理类$Proxy0是Proxy的子类且实现了目标对象的接口。代理类对象实现了代理目标的所有接口,并代替目标对象进行实际的操作。但这种代替不是一种简单的代替,这样没有任何意义,代理的目的是在目标对象方法的基础上作增强,这种增强的本质通常就是对目标对象的方法进行拦截。所以,代理类应该包括一个方法拦截器,来指示当拦截到方法调用时作何种处理。InvocationHandler就是拦截器的接口。

InvocationHandler接口中声明的方法为:Object invoke(Object proxy,Method method,Object[] args);

这个接口有三个参数,后两个比较容易理解,method是被拦截的方法,args是该方法的参数列表。关键是第一个参数,由javadoc可知它是一个代理实例并且它是一个实现了目标对象接口的对象,而不同于目标对象。也就是说代理机制是面向接口的。

首先依然是Seller接口和Tailor委托类(代码见上)。

然后是实现InvocationHandler接口的拦截器类。

package proxypattern;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class Interceptor implements InvocationHandler {

	private Tailor tailor; // 拦截器中存放tailor引用,用以操作tailor

	public Interceptor(Seller tailor) {
		this.tailor = (Tailor) tailor;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		// TODO Auto-generated method stub
		System.out.println("我是代理,拦截到让裁缝做西服的请求。");
		doSomethingBefore(); // 在执行method前干点儿什么事儿

		method.invoke(tailor, args); // 拦截到method

		doSomethingAfter(); // 在执行完method后也可以干点儿事儿
		return null;
	}

	private void doSomethingAfter() {
		// TODO Auto-generated method stub
		System.out.println("我是代理,在裁缝做完西服,做点儿额外的事儿,试衣服,交剩下的钱。");
	}

	private void doSomethingBefore() {
		// TODO Auto-generated method stub
		System.out.println("我是代理,在让裁缝做西服前,做点儿额外的事儿:谈价格、交定金。");
	}

}
最后就可以用Proxy静态类创建代理对象了,不清楚的地方仔细看看代码中的注释。

package proxypattern;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class Client {

	/**
	 * @param args
	 * @throws Throwable
	 * @throws NoSuchMethodException
	 */
	public static void main(String[] args) throws Throwable {
		// TODO Auto-generated method stub
		Tailor tailor = new Tailor();
		// invocationhandler实现类,里面包含了委托类的引用
		InvocationHandler handler = new Interceptor(tailor);

		/**
		 * 获得代理类($Proxy0 extends Proxy implements Seller)的实例
		 */
		// 生成一个代理类的Class对象
		Class cls = Proxy.getProxyClass(tailor.getClass().getClassLoader(),
				tailor.getClass().getInterfaces());
		// /获得代理类的构造函数,便于下一步构造代理类对象。
		// 由于代理类是继承了Proxy的,这里获取继承的构造函数:protected Proxy(InvocationHandler h)
		Constructor constructor = cls
				.getConstructor(new Class[] { InvocationHandler.class });
		// 得到构造函数后就可以构造代理类对象啦~~
		Seller seller = (Seller) constructor
				.newInstance(new Object[] { handler });
		seller.workOnSuite();

		// // 或者一步到位,直接得到代理类对象
		// seller = (Seller) Proxy.newProxyInstance(tailor.getClass()
		// .getClassLoader(), tailor.getClass().getInterfaces(), handler);
		// // 代理类是继承自委托类的,所以调用代理类的request函数,就执行了委托类的request函数。
		// seller.workOnSuite();
	}

}

输出:

我是代理,拦截到让裁缝做西服的请求。
我是代理,在让裁缝做西服前,做点儿额外的事儿:谈价格、交定金。
我是裁缝,我正在做一套西服。
我是代理,在裁缝做完西服,做点儿额外的事儿,试衣服,交剩下的钱。

可以把上面代码中最后部分的注释去了,等价于它上面创建动态代理对象的过程,只是更简洁,一步到位,结果是一样的。

有两篇文章个人认为对于深入理解java动态代理很有价值,在这里也感谢作者的分享:

第一篇:JDK的动态代理深入解析(Proxy,InvocationHandler)

第二篇:java 动态代理深度学习(Proxy,InvocationHandler),含$Proxy0源码

Beyond Compare是一款文件差异比较工具的文件和文件夹比较工具,使用该工具可以可视化和调整差异, 合并修改,同步文件夹。支持文件夹比较,文件夹合并和同步,文本比较,表格比较,图片比较,16进制比较,注册表比较,版本比较等;调整差异,合并修改,内置文件浏览器可以针对文件、文件夹之间的差异对比及上传同步。 Beyond Compare 5.0.4.30422是一款先进的文件和文件夹比较工具,它能够帮助用户高效地识别和管理文件差异,支持多种文件类型和格式的比较。使用Beyond Compare,用户可以轻松地对文件夹内容进行同步,无论是进行简单的文件复制还是复杂的项目同步任务。此外,该工具还具备了高级的文件比较功能,如文本比较、表格比较、图片比较、16进制比较以及注册表比较,覆盖了从纯文本到二进制文件的广泛使用场景。 对于文本文件的比较,Beyond Compare提供了语法高亮和行号等辅助功能,让用户在审查代码或文档时能更快地定位差异点。表格比较功能则特别适用于数据分析和处理任务,可以快速识别两个Excel电子表格之间的不同之处。在进行图片文件的比较时,用户可以通过直观的视图了解图片之间的微小差别,这在图像处理和质量控制中尤其有用。 此外,16进制比较功能为开发者提供了深入分析二进制文件差异的手段,无论是在软件开发还是在数据恢复方面都大有裨益。注册表比较则专注于Windows系统的核心配置文件,帮助IT专业人员快速定位系统配置的变化,这对于系统维护和故障排除尤其重要。 Beyond Compare内置的文件浏览器允许用户在一个界面内完成文件的浏览、比较和同步操作,极大的提高了工作效率。内置的差异调整和合并修改功能让同步文件夹的工作更加精确和便捷。用户可以针对不同的文件和文件夹进行个性化设置,实现定制化的比较和同步策略。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值