快速发展的开发人员社区、对各种后端技术(包括JMS、JTA、JDO、Hibernate、iBATIS等等)的支持,以及(更为重要的)非侵入性的轻量级IoC容器和内置的AOP运行时,这些因素使得SPRing Framework对于J2EE应用程序开发十分具有吸引力。Spring托管的组件(POJO)可以与EJB共存,并答应使用AOP方法来处理企业应用程序中的横切方面——从监控和审计、缓存及应用程序级的安全性开始,直到处理特定于应用程序的业务需求。
本文将向您介绍Spring的AOP框架在J2EE应用程序中的实际应用。
简介
J2EE技术为实现服务器端和中间件应用程序提供了坚实的基础。J2EE容器(比如BEA WebLogic Server)可以治理系统级的元素,包括应用程序生命周期、安全性、事务、远程控制和并发性,而且它可以保证为JDBC、JMS和JTA之类的常见服务提供支持。然而,J2EE的庞大和复杂性使开发和测试变得异常困难。传统的J2EE应用程序通常严重依靠于通过容器的JNDI才可用的服务。这意味着需要大量直接的JNDI查找,或者要使用Service Locator模式,后者稍微有所改进。这种架构提高了组件之间的耦合度,并使得单独测试某个组件成为几乎不可能实现的事情。您可以阅读Spring Framework创建者所撰写的J2EE Development without EJB一书,其中深入分析了这种架构的缺陷。
借助于Spring Framework,可以将使用无格式java对象实现的业务逻辑与传统的J2EE基础架构连接起来,同时极大地减少了访问J2EE组件和服务所需的代码量。基于这一点,可以把传统的OO设计与正交的AOP组件化结合在一起。本文稍后将会演示如何重构J2EE组件以利用Spring托管的Java对象,然后应用一种AOP方法来实现新特性,从而维护良好的组件独立性和可测试性。
与其他AOP工具相比,Spring提供了AOP功能中的一个有限子集。它的目标是紧密地集成AOP实现与Spring IoC容器,从而帮助解决常见的应用问题。该集成是以非侵入性的方式完成的,它答应在同一个应用程序中混合使用Spring AOP和表现力更强的框架,包括aspectJ。Spring AOP使用无格式Java类,不要求非凡的编译过程、控制类装载器层次结构或更改部署配置,而是使用Proxy模式向应该由Spring IoC容器托管的目标对象应用通知。
可以根据具体情况在两种类型的代理之间进行选择:
第一类代理基于Java动态代理,只适用于接口。它是一种标准的Java特性,可提供卓越的性能。
第二类代理可用于目标对象没有实现任何接口的场景,而且这类接口不能被引入(例如,对于遗留代码的情况)。它基于使用CGLIB库的运行时字节码生成。
对于所代理的对象,Spring答应使用静态的(方法匹配基于确切名称或正则表达式,或者是注释驱动的)或动态的(匹配是在运行时进行的,包括cflow切入点类型)切入点定义指派特定的通知,而每个切入点可以与一条或多条通知关联在一起。所支持的通知类型有几种:环绕通知(around advice),前通知(before advice),返回后通知(after returning advice),抛出异常后通知(after throwing advice),以及引入通知(introdUCtion advice)。本文稍后将给出环绕通知的一个例子。想要了解更具体的信息,可以参考Spring AOP框架文档。
正如先前提到的那样,只可以通知由Spring IoC容器托管的目标对象。然而,在J2EE应用程序中,组件的生命周期是由应用服务器托管的,而且根据集成类型,可以使用一种常见的端点类型把J2EE应用程序组件公开给远程或本地的客户端:
无状态的、有状态的或实体bean,本地的或远程的(基于RMI-IIOP)
监听本地或外部JMS队列和主题或入站JCA端点的消息驱动bean(MDB)
Servlet(包括Struts或其他终端用户UI框架、xml-RPC和基于SOAP的接口)
图 1.常见的端点类型
要在这些端点上使用Spring的AOP框架,必须把所有的业务逻辑转移到Spring托管的bean中,然后使用服务器托管的组件来委托调用,或者定义事务划分和安全上下文。虽然本文不讨论事务方面的问题,但是可以在“参考资料”部分中找到相关文章。
我将具体介绍如何重构J2EE应用程序以使用Spring功能。我们将使用XDoclet的基于JavaDoc的元数据来生成home和bean接口,以及EJB部署描述符。可以在下面的“下载”部分中找到本文中所有示例类的源代码。