APP下载

代理软件设计模式及其应用研究

2012-01-04崔行臣

山东开放大学学报 2012年3期
关键词:拦截器设计模式调用

崔行臣

(山东广播电视大学现代教育技术中心,山东 济南 250014)

代理软件设计模式及其应用研究

崔行臣

(山东广播电视大学现代教育技术中心,山东 济南 250014)

代理设计模式是软件开发中使用最广泛的软件设计模式之一。本文首先介绍了软件设计模式的思想、应用场合和实现方式,然后对java中的动态代理进行了深入研究,最后探讨了动态代理设计模式在Struts、AOP、Hibernate等方面的应用。实践证明,代理设计模式在软件架构开发中体现了责任清晰,高扩展和智能化等优点。

代理设计模式;动态代理;AOP

软件设计模式是从许多优秀的软件系统中总结出的成功的可复用的设计方案。设计模式依据其工作目的可分为创建型(Creational)、结构型(Structural)、和行为型(Behavioral)三种。代理设计模式属于结构型软件设计模式,代理模式给某一个对象提供一个代理对象,让代理对象控制某对象的访问,被代理的对象可以是远程的对象、创建开销大的对象或需要安全控制的对象。

Java动态代理机制的出现,使得 Java开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类。代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过程中,开发人员还可以按需调整委托类对象及其功能,这是一套非常灵活有弹性的代理框架。

本文首先从代理模式的设计思想分析开始,对代理模式的使用场景进行了总结,然后对Java动态代理的运行机制和特点进行了分析,最后对动态代理模式在 struts2、Spring AOP、Hibernate和数据源方面的应用进行了深入探讨。

1.代理设计模式概述

1.1 代理模式设计思想

代理软件模式定义:provide a surrogate or placeholder for another object to control access to it.为其他对象提供一种代理以控制对这个对象的访问。

代理模式是一种应用非常广泛的设计模式,设计思想就是为某一个对象的访问提供一个代理对象,而不是直接去控制这个对象。在某些情况下,客户端代码不想或不能够直接调用被调用者,此时我们就可返回该对象的代理(Proxy)。在这种设计方式下,系统会为某个对象提供一个代理对象,并由代理对象控制对源对象的引用,代理对象可以在客户和目标对象之间起到中介的作用。对客户端而言,它不能也无须分辨出代理对象与真实对象的区别。客户端代码并不知道真正的被代理对象,客户端代码面向接口编程,它仅仅持有一个被代理对象的接口。

1.2 代理模式角色

抽象主题角色(Subject):声明真实对象和代理对象的共同接口,是一个最普通的业务类型定义。

代理主题角色(Proxysubject):也叫代理类。它负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在真实主题角色处理完毕前后做预处理和善后处理工作。

具体主题角色(Realsubject):也叫被代理角色,代理角色所代表的真实对象,即业务的具体执行者[1]。

代理各角色及代理模式架构图如图1所示:

图1 代理设计模式

1.3 代理的分类及使用场景

根据使用目的或使用场景来划分,代理可以分为以下几种:

(1)远程(Remote)代理:远程方法调用,为一个位于不同的地址空间的对象提供一个局域代表对象[1]。

(2)虚拟(Virtual)代理:目标对象只在需要时才会被真正创建,此时目标对象通常为资源消耗较大的对象,可以避免被代理对象较多而引起初始化缓慢的问题,能显著提高系统的性能。代理对象和被代理对象实现同一的接口。当程序需要使用目标对象时并不是直接返回objectA对象,而是先返回proxyObjectA对象,当控制逻辑真正调用被调用对象的某一方法时,才真正创建被代理的objectA对象。

(3)保护(Protect or Access)代理:控制对一个对象的访问,如果有需要,可以给不同的用户提供不同级别的使用权限。

(4)智能引用代理:当目标对象被引用时,提供一些额外操作用来增强目标对象的功能。这种增强的本质就是对目标对象的方法进行拦截和过滤。借助于Java提供的Proxy和InvocationHandler,可以实现在运行时生成动态代理的功能,而动态代理对象就可作为目标对象使用,而且增强了目标对象的功能。

(5)Cache代理:为某一目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。

(6)防火墙代理:保护目标,不让恶意用户接近。

代理在实现方式上可以分为静态代理和动态代理。静态代理在源码级实现,而动态代理在运行时实现。

2.JDK动态代理

JVM生成的动态代理类必须实现一个或多个接口,所以JVM生成的动态类只能用作具有相同接口的目标类的代理,如果要为一个没有实现接口的类生成动态代理类,可以使用CGLIB库,CGLIB库可以动态生成一个类的子类用作该类的代理。Java语言通过java.lang.reflect库中,提供3个类来支持代理模式[2]:Proxy,InvocationHandle和Method。

(1)InvocationHandler:该接口中仅定义了一个方法Object:invoke(Object obj,Method method,Object[]args) throws Throwable。在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如图2中的request(),args为该方法的参数数组。这个抽象方法在代理类中动态实现。

(2)Proxy:该类即为动态代理类,作用类似于图1的ProxySubject,其中主要包含以下内容:

Protected Proxy(InvocationHandler h):唯一的构造函数,用于给内部的成员变量h赋值。

Static Class getProxyClass(ClassLoader loader,Class[]interfaces):获得一个代理类,其中 loader是类装载器,interfaces是真实类所拥有的全部接口的数组。

Static ObjectnewProxyInstance(ClassLoaderloader,Class[]interfaces,InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)。

动态代理类及其实例通过 Proxy中的静态方法newProxyInstance来创建,相当于在内存中动态产生了一个代理类 $Proxy0,然后再实例化,两步骤合二为一。$Proxy0类只有一个构造方法$Proxy0(java.lang.reflect. InvocationHandle)。因为是在内存中动态产生的类,所以需要明确指定类加载器。这个代理类要实现一定的接口,动态代理实例中的对接口的调用都转发给代理的调用处理器InvocationHandle的invoke()方法来完成真正的方法调用,该方法在调用目标方法之前后或异常处理中增加额外功能。即:每执行一次目标类的方法便执行一次invoke方法。例如,调用ArrayList类的add方法,那么JVM生成的动态代理类内部实现为:

Java动态代理的通用类图如图2所示:

使用梁单元建立Midas Civil分析模型,填料采用弹性连接与节点荷载模拟,取填料重度22 kN/m3,主拱圈、立柱、腹拱、桥面系均采用C40素混凝土模拟,护栏作为二期恒载加载,腹拱与立柱、主拱圈为主从节点刚性连接,固定约束主拱圈拱脚。拱桥分析双单元模型如图4所示。

图2 动态代理类图

3.代理设计模式应用

3.1 动态代理在struts2拦截器中的应用

拦截器体系是struts2的一个重要组成部分,正是大量的内建拦截器完成了该框架的大部分操作。拦截器也就是个普通的java类,之所以称其为拦截器,只是就他的行为而言的。拦截器可以动态地拦截发送到指定Action的请求,通过拦截器机制可以在Action的前后插入某些代码。通过这种方式,就可以把多个action中需要重复指定的代码提取出来,放在拦截器里定义,从而更好的提供代码重用性。

Struts框架之所以能够调用拦截器的方法,调用哪一个拦截器,是因为拦截器的方法都是通过代理的方式调用的。代理类实现在调用目标方法的前后分别调用拦截器中的方法,主要借助于Proxy类和InvocationHandler接口来实现,JDK动态代理的关键在于下面的MyInvokation-Handler类,该类是一个InvocationHandler实现类,该实现类的invoke方法将会作为代理对象的方法实现。

invoke方法通过反射机制回调了被代理对象的目标方法,在调用目标方法前后分别附加了功能(也可以在异常处理中附加功能)。通过这种方式,使得代理对象的方法既回调了被代理对象的方法,并为被代理对象的方法增加其他功能。通过上面的代理处理器类可以看出类与拦截对象没有丝毫耦合,从而提供了更好的解耦以及更好的扩展。但上面和两个地方耦合了:(1)与拦截器类耦合,上面类固定使用了XXIntercepter拦截器;(2)与被拦截方法耦合。正是通过这两个地方的耦合,系统才能够知道在调用哪个拦截器的方法,以及需要拦截的目标对象,解决这二个耦合的方案是将拦截器类和需要被拦截的目标方法都放到配置文件中。

代理工厂负责根据目标对象和对应的拦截器生成新的代理对象,代理对象里的方法是目标方法和拦截器方法的组合。所以采用动态代理可以非常灵活地实现解耦[3]。

这种动态代理在AOP(Aspect Orient Program,面向切面编程)里被称为AOP代理。AOP的核心思想就是将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。AOP从关注点的角度考虑问题,关注点也就是要考察或解决的问题。AOP把一个系统分解成不同的关注点,核心的业务逻辑称为核心关注点,而一些分散在各个部分辅助的关注点称为横切关注点。核心关注点通过面向对象的方式来实现,横切关注点通过AOP的方式来实现,比如记录日志、安全验证等横切关注点就可以通过AOP的方式来实现[4]。Spring的AOP实现就是基于动态代理实现的。

在一般软件开发中,通常在一些业务逻辑中有些共用功能模块,如:安全,事物,日志等,这些功能贯穿到好几个模块中,我们称其为交叉业务。AOP的目标就是使得交叉业务模块化,使这些模块移到原始方法的周围,作为一个切面,这与在方法中编写切面代码的运行效果是一样的。AOP是从程序的运行角度来考虑程序的流程,在程序特定的切面通过系统自动插入特定代码[5]。

3.2 代理模式在Hibernate延迟加载中的应用

Hibernate采用“延迟加载”管理关联实体的模式,其实就在加载主实体时,并未真正去抓取关联实体对应数据,而只是动态地生成一个对象作为关联实体的代理。当应用程序真正需要使用关联实体时,代理对象会负责从底层数据库抓取记录,并初始化真正的关联实体。在Hibernate的延迟加载中,客户端程序开始获取的只是一个动态生成的代理对象,而真正的实体则委托给代理对象来管理。

Hibernate的延迟加载(lazy load)本质上就是代理模式的应用,通过以上介绍得知,经常通过代理模式来降低系统的内存开销、提升应用的运行性能。Hibernate充分利用了代理模式的这种优势,并结合了 Javassist或 CGLIB来动态地生成代理对象,这更加增加了代理模式的灵活性。

3.3 代理模式在数据库连接池中的应用

采用数据库连接池技术的资源释放与传统JDBC方式不同,用户使用完连接之后再放到连接池中而不是销毁,如果用户在取出数据后,调用了connection的close方法,则该连接就会被销毁,这就和连接池技术相违背了。通常认为,用继承的方法可以解决,即通过继承各种关系数据库驱动的connection类,重写其中close方法即可。但这种方法有其局限性,一是因为难以扩展,各数据库厂商的connection类不一样,二是有些数据库驱动的connection方法不允许继承。为了解决此问题,需要使用代理模式来解决,即定义一个连接类 Myconnection作为代理,实现java.sql.connection类,重写close()方法,根据“组合优先继承”的思想,把真实的数据库连接组合到Myconnection中类驱动数据库。这样在数据源MyDataSource中创建连接时,以构造方法中传入具体连接类,代码如下:

如果采用动态代理实现,需要定义一个调用处理器来实现上述Myconnection的功能:

这样在数据源MyDataSource中创建连接时,用调用处理器来绑定真实连接,代码如下:

4.小结

代理设计模式在软件开发中是使用较多的一种设计模式,java提供的动态代理应用比较广泛,大到一个系统框架、企业平台,小到代码片段、事物处理,而且有了AOP的编程方式,代理使用就更加简单了。通过以上分析可知,代理设计模式优点主要有:

(1)职责清晰。真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,其它事物可以通过后期的代理来完成,附带的结果就是编程简洁清晰。

(2)高扩展性。具体主题角色是随时都会发生变化的,只要它实现了接口,不管它如何变化,代理类完全就可以在不做任何修改的情况下使用。

(3)智能化。代理的智能化体现在动态代理模式。

[1](美)弗里曼(Freeman,E.),等.Head First设计模式(中文版)[M].北京:中国电力出版社,2007.

[2]JDK api文档[EB/OL].http://docs.oracle.com/ javase/6/docs/api/.

[3]李刚.Struts2.1权威指南——基于webwork核心的MVC开发[M].北京:电子工业出版社,2009.

[4]曹晓利,郭顺生.AOP技术及其在J2EE中的动态代理实现[J].计算机技术与发展,2008,18(11):120-122.

[5]王小民,杨志辉,张雄,等.结合AOP与反射机制动态改变软件的行为[J].计算机科学,2007,34(11):274 -278.

TP311

A

1008—3340(2012)03—0066—04

2012-03-26

崔行臣,山东聊城人,硕士,研究方向为软件方法与技术。

猜你喜欢

拦截器设计模式调用
多动能拦截器协同制导规律的研究及仿真
英国MARSS公司推出新型反无人机拦截器
以色列“天锁”公司展出新式反无人机拦截器
“1+1”作业设计模式的实践探索
三维协同设计模式下的航天项目管理实践与展望
核电项目物项调用管理的应用研究
LabWindows/CVI下基于ActiveX技术的Excel调用
交通机电工程设计模式创新探讨
基于系统调用的恶意软件检测技术研究
互动式设计模式研究