事务管理
抽象出一个数据访问的API是不够的;我们还需要考虑事务管理。JTA是显而易见的选择,但是它是一个直接用起来很笨重的API,因而许多J2EE开发者感到EJB CMT是对于事务管理唯一合理的选择。
Spring提供了它自己对事务管理的抽象。Spring提供了这些:
通过类似于JdbcTemplate的回调模板编程管理事务,比起直接使用JTA要容易多了
类似于EJB CMT的声明式事务管理,但是不需要EJB容器
Spring的事务抽象式唯一的,它不绑定到JTA或者任何其他事务管理技术。Spring使用事务策略的概念把程序代码和底层的事务架构(例如JDBC)解藕。
为什么你要关心这些?JTA不是所有事务管理的最好答案吗?如果你正在编写仅仅使用一个数据库的程序,你不需要JTA的复杂度。你不关心XA事务或者两阶段提交。你甚至不需要提供这些东西的高端应用服务器。但是另一方面,你不会希望在需要和多个数据源打交道的时候重写你的代码。
假定你决定通过直接使用JDBC或者Hibernate的事务以避免JTA带来的额外负担。一旦你需要处理多个数据源,你必须剥开所有的事务管理代码并且使用JTA事务来替代。这不是非常有吸引力的并且导致大部分J2EE程序员,包括我自己,推荐只使用全局JTA事务。然而使用Spring事务抽象,你只需要重新配置Spring让它使用JTA,而不是JDBC或者Hibernate的事务策略,就一切OK了。这是一个配置上的改变,而不是代码的改动。因而,Spring使得你能够自由缩放应用。 AOP
最近在应用AOP来解决企业关注点方面大家有了很大的兴趣,例如事务管理,这些都是EJB所要解决的。
Spring的AOP支持的首要目标是要给POJOs提供J2EE服务。这类似于JBoss 4的目标,Spring AOP由它能够在应用服务器之间移植的优势,因而没有绑死在厂商身上的风险。它既可以在web或者EJB容器中使用,也能够在WebLogic,Tomcat,JBoss,Resin,Jetty,Orion和许多其他应用服务器和web容器上使用。
Spring AOP支持method interception。所支持关键的AOP概念包括:
Interception:自定义行为能够在对接口和类的调用之前和之后插入。这类似于AspectJ术语中类似的“around advice”。
Introduction:指定advice会导致对象实现额外的接口。这混乱了继承。
静态和动态的pointcuts:在interception发生的程序执行处指定points。静态pointcuts concern函数签名;动态pointcuts也可以在point被求值的地方考虑函数的参数。Pointcuts独立interceptors单独定义,使得标准interceptor可以应用于不同应用程序和代码上下文。
Spring既支持有状态(一个advised对象一个实例)也支持无状态的interceptors(所有advice使用一个实例)。
Spring不支持field interception。这是一个经过深思熟虑的设计决定。我总是感觉field interception违反了封装。我比较倾向于把AOP作为补全物,而不是与OOP冲突的东西。如果在5年或者10年后,我们在AOP学习曲线上走得更远了并且觉得应该在程序设计的桌面上给AOP一个位置,我不会惊讶的。(然而在那个时候基于语言的解决方案例如AspectJ可能比它们今天看来更加具有吸引力。)
Spring使用动态代理实现AOP(其中存在一个接口)或者在运行时使用CGLIB生成字节码(这使得能够代理类)。两种方法都能够在任何应用服务器中使用。
Spring是第一个实现AOP Alliance interfaces的AOP 框架(www.sourceforge.net/projects/aopalliance)。这些是定义在不同AOP框架中能够互操作interceptors的尝试。
在TheServerSide和其他地方有一个正在进行但是不是那么引人注目的争论,就是这种interception是不是“true AOP”。我倒不怎么在意它叫什么;仅仅需要知道它是否在实践中有用就好了。我也乐于称它为“declarative middleware”(声明式中间件)。把Spring AOP认做简单,轻量级的无状态beans的替代物,这样就不需要monolithic EJB容器了,而这些仅仅是让你能够构建有你需要的服务的容器。我不推荐advising任何一个POJO,对local SLSBs的类比有助于你理解推荐的粒度。(然而,与EJB不同的是,在恰当但是少见的情况下,你可以自由地把Spring的AOP应用到粒度更好的对象上。)
因为Spring在实例上advises 对象,而不是在class loader层面上,使用有不同advice的同一个类的多个实例是可能的,或者与advised实例一道使用unadvised 实例。
可能Spring AOP最常见的应用是声明式事务管理。这是基于前面描述的TansactionTemplate抽象上的,并且可以给任何POJO提供声明式事务管理。取决于事务策略,底层的机制可以是JTA,JDBC,Hibernate或者任何其他提供事务管理的API。
Spring的声明式事务管理类似于EJB CMT,在以下方面有些不同:
事务管理能够应用于任何POJO。我们推荐业务对象实现接口,但是这只是一个好的编程习惯的问题,而不是由框架强制的。
通过使用Spring的事务API能够在事务性POJO中实现编程回调。我们为此提供静态的方法,使用ThreadLoacal变量,因而你不需要传播诸如EJBContext这样的context对象来确保回滚。
你可以声明式地定义“回滚规则”。EJB不会在未捕捉程序异常的时候自动回滚(仅仅在unchecked exceptions和其他Throwables的时候),应用程序开发者经常需要在任何异常发生时回滚。Spring事务管理让你能够声明式地指定什么异常什么子类能够导致自动回滚。缺省的行为和EJB是一致的,但是你能够在checked和unchecked异常时自动回滚。这个在最少化自编程回调代码方面有很大好处,而回调依赖于Spring的事务API(因为EJB的编程回调时在EJBContext中完成的)。
事务管理不绑定于JTA。如前面解释过的,Spring的事务管理能够在不同事务策略中使用。
当然还可以使用Spring AOP实现程序特有的aspects。取决于你对AOP概念的接受程度,决定你是否选择这么做,而不是Spring的能力,但是它确实非常有用。我们所见过的成功例子包括:
自定义的security interception,当安全检查的复杂度超出了J2EE安全架构的能力的时候
在开发中使用的调试和profiling aspects
发送email通知管理员用户不寻常的举动的Interceptors
程序自定的aspects能够成为消除需要许多函数的样板代码的有利武器。
Spring AOP透明地与Spring BeanFactory概念集成。包含一个来自Spring BeanFactory对象地代码不需要知道它是还是不是advised。和任何对象一样,契约实在接口和对象实现中定义的。
下面的XML片断展示了如何定义一个AOP代理:
代码: |
<bean id="myTest" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>org.springframework.beans.ITestBean</value> </property> <property name="interceptorNames"> <list> <value>txInterceptor</value> <value>target</value> </list> </property> </bean>
|
注意bean类的定义总是AOP框架的ProxyFactoryBean,虽然bean的类型在引用中使用或者由BeanFactory的getBean()方法返回时依赖的是代理接口。(多个代理方法是被支持的。)ProxyFactoryBean的“interceptorNames”属性需要一个字符串列表。(因为如果代理是一个“prototype”而不是singleton,有状态interceptors可能需要创建新的实例,所以必须使用Bean的名字而不是bean的引用。)列表中的名字可以是interceptor或者pointcuts(interceptors和有关它们合适被使用的信息)。列表中的“target”值自动创建一个“invoker interceptor”封装target对象。实现代理接口的是在factory中的bean的名字。这个例子中的myTest可以和其他bean factory中的bean一样使用。例如,其他对象可以使用<ref>元素引用它而且这些引用是由Spring IoC设置的。
还可以不用BeanFactory,编程构建AOP代理,虽然这个很少用得上:
代码: |
TestBean target = new TestBean(); DebugInterceptor di = new DebugInterceptor(); MyInterceptor mi = new MyInterceptor(); ProxyFactory factory = new ProxyFactory(target); factory.addInterceptor(0, di); factory.addInterceptor(1, mi); // An "invoker interceptor" is automatically added to wrap the target ITestBean tb = (ITestBean) factory.getProxy();
|
我们相信最好把程序装配从Java代码中移出来,而AOP也不例外。
Spring在它的AOP能力方面的直接竞争者是Jon Tirsen的Nanning Aspects(http://nanning.codehaus.org)。
我觉得AOP作为EJB的替代无提供企业服务这个用法方面的进步是重要的。随着时间,这将成为Spring很重要的关注点。
posted on 2005-10-26 15:56
Sung 阅读(227)
评论(0) 编辑 收藏 所属分类:
Java