AspectJ 方式來處理 Spring 的 @Transactional 註解式事務(轉)

在網絡應用中,我們幾乎總是需要嚴密控制我們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。 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章