AspectJ 方式来处理 Spring 的 @Transactional 注解式事务(转)

来源:互联网 发布:淘宝宝贝详情模板psd 编辑:程序博客网 时间:2024/04/30 00:25

用 AspectJ 方式来处理 Spring 的 @Transactional 注解式事务

关键字: 事务处理 aspectj spring

为节省你的时间, 如果你你不清楚什么是Spring 、AspectJ、事务处理,本文就不适合你看。你可以路过就走。

 

在网络应用中,我们几乎总是需要严密控制我们spring应用中的数据库事务的启动和结束。为做到这一点,我们或多或少都已经通过AOP来做这些事情。但一般都是在XXService、或XXController中封装处理请求的方法。

Spring有内置注解支持,因而你可以简单地通过@Transactional 注解你的方法或类,并在配置文件中添加<tx:annotation-driven />,把相应方法封装于一个事务之中。这听起来好像很简单

 

但是,所有这些都是通过Spring 的代理对象封装并环绕增强原来的被注解@Transactional 的类来实现的,但这种做法只有当事务方法是public的、并且是被代理类外部调用的情况下才会正常工作(可以参看Spring 事务处理模型图就明白,否则代理对象自己调用自己就会绕过对它的环绕事务增强,其他切面增强也是一样)。这就很不爽了,意味着你不能在XXService或XXController内部串联处理一些具各自独立的事务,例如在XXController调用handleRequestInternal。解决的办法是使用全功能完整成熟的AspectJ织入。AspectJ织入方式同样支持@Transactional (其他自定义注解也行^_^),同时能被织入到所有方法中(不只是public),并且在内不外部都可以。

 

AspectJ有三种方式织入事务代码

a.编译时(CTW). 拥有所有需要的源代码

b.运行时(LTW).

c.字节码织入(BTW).没有织入目标的源代码(如只有jar)

 

这里我们使用CTW的方式

Xml代码 复制代码
  1. <beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop">  
  2.   
  3.     <aop:spring-configured>  
  4.   
  5.     <bean id="annotationTransactionAspect" factory-method="aspectOf"  class="org.springframework.transaction.aspectj.AnnotationTransactionAspect">  
  6.         <property name="transactionManager" ref="transactionManager"></property>  
  7.     </bean>  
  8.   
  9.     <!-- the rest of your application here -->  
  10. </beans>  

 上面就是所有让Spring 使用Aspectj 方式@Transactional 注解事务的所有配置了。

 

下面我们开始把环绕事务切面的增强代码织入到注解了@Transactional  的XXService、或XXController类中(其他任何注解了@Transactional  也可以)。我们使用ant来构建织入。我们写一个ant任务来做这件事

Xml代码 复制代码
  1. <target name="compileAndWeave">  
  2.   
  3.     <path id="web-src.compile.class.path">  
  4.         <!-- 指定编译时所需要的任意库, 包括AspectJ所需要的jar -->  
  5.         <path refid="external.libs.path" />  
  6.     </path>  
  7.   
  8.     <!-- 正常地编译你的源代码到这个目录中-->  
  9.     <javac srcdir="src"  destdir="build/classes-preweave"  classpathref="web-src.compile.class.path" />  
  10.   
  11.     <!-- 查找"iajc" task -->  
  12.     <taskdef resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties"  classpath="path/to/aspectj/aspectjtools.jar"/>  
  13.   
  14.     <!-- weave the just compiled classes from classes-preweave into classes -->  
  15.     <iajc  inpath="build/classes-preweave"  
  16.              destdir="build/classes"                                          <!--正常javac编译的*.class文件,也就是我们注解了@Transactional  的XXService、或XXController类所在位置-->  
  17.              aspectpath="path/to/spring/spring-aspects.jar"   <!--AspectJ切面类所在位置如:org.springframework.transaction.aspectj.AnnotationTransactionAspect切面的位置-->  
  18.              classpathref="web-src.compile.class.path"        
  19.             verbose="true" />  
  20.   
  21. </target>  

  

 编译后把你的war发布到任何web容器中他就能工作了,所有注解了@Transactional  的方法(各种可见度)都能正常的处理事务,如果是类级@Transactional  注解,该类的就所有public方法都有事务。而且被注解类的内外都能调用,这样,你完全可以撇开spring那麻烦的代理了,还补充一句,如果你使用了DWR做为你的ajax后台的话,服务层如果是JDK代理的话,将无法工作。只能使用Cglib方式的代理。还有很多情况,Spring 代理模式和其他一些框架配合工作的时候会有问题,全部使用AspectJ,撇开Spring 代理模式,你会觉得真的很free。 

原创粉丝点击