class="type_original" title="原创">用 AspectJ 方式来处理 Spring 的 @Transactional 注解式事务
关键字: 事务处理 aspectj class="tags" href="/tags/SPRING.html" title=spring>spring
为节省你的时间, 如果你你不清楚什么是Spring 、AspectJ、事务处理,本文就不适合你看。你可以路过就走。
在class="tags" href="/tags/WangLuoYingYong.html" title=网络应用>网络应用中,我们几乎总是需要严密控制我们class="tags" href="/tags/SPRING.html" title=spring>spring应用中的数据库事务的启动和结束。为做到这一点,我们或多或少都已经通过AOP来做这些事情。但一般都是在XXService、或XXController中封装处理请求的方法。
Spring有内置注解支持,因而你可以简单地通过@Transactional 注解你的方法或类,并在配置文件中添加<tx:annotation-driven />,把相应方法封装于一个事务之中。这听起来好像很简单。
但是,所有这些都是通过Spring 的代理对象封装并环绕增强原来的被注解@Transactional 的类来实现的,但这种做法只有当事务方法是public的、并且是被代理类外部调用的情况下才会正常class="tags" href="/tags/GongZuo.html" title=工作>工作(可以参看Spring 事务处理模型图就明白,否则代理对象自己调用自己就会绕过对它的环绕事务增强,其他切面增强也是一样)。这就很不爽了,意味着你不能在XXService或XXController内部串联处理一些具各自独立的事务,例如在XXController调用handleRequestInternal。解决的办法是使用全功能完整成熟的AspectJ织入。AspectJ织入方式同样支持@Transactional (其他自定义注解也行^_^),同时能被织入到所有方法中(不只是public),并且在内不外部都可以。
AspectJ有三种方式织入事务代码
a.编译时(CTW). 拥有所有需要的源代码
b.运行时(LTW).
c.字节码织入(BTW).没有织入目标的源代码(如只有jar)
这里我们使用CTW的方式
- class="dp-xml">
- class="tag"><class="tag-name">beans class="attribute">xmlns=class="attribute-value">"http://www.class="tags" href="/tags/SPRING.html" title=spring>springframework.org/schema/beans" class="attribute">xmlns:class="tags" href="/tags/AOP.html" title=aop>aop=class="attribute-value">"http://www.class="tags" href="/tags/SPRING.html" title=spring>springframework.org/schema/class="tags" href="/tags/AOP.html" title=aop>aop"class="tag">>
- class="tag"><class="tag-name">class="tags" href="/tags/AOP.html" title=aop>aop:class="tags" href="/tags/SPRING.html" title=spring>spring-configuredclass="tag">>
- class="tag"><class="tag-name">bean class="attribute">id=class="attribute-value">"annotationTransactionAspect" class="attribute">factory-method=class="attribute-value">"aspectOf" class="attribute">class=class="attribute-value">"org.class="tags" href="/tags/SPRING.html" title=spring>springframework.transaction.aspectj.AnnotationTransactionAspect"class="tag">>
- class="tag"><class="tag-name">property class="attribute">name=class="attribute-value">"transactionManager" class="attribute">ref=class="attribute-value">"transactionManager"class="tag">>class="tag"></class="tag-name">propertyclass="tag">>
- class="tag"></class="tag-name">beanclass="tag">>
- class="comments"><!-- the rest of your class="tags" href="/tags/APPLICATION.html" title=application>application here -->
- class="tag"></class="tag-name">beansclass="tag">>
class="xml" style="display: none;"><beans xmlns="http://www.class="tags" href="/tags/SPRING.html" title=spring>springframework.org/schema/beans" xmlns:class="tags" href="/tags/AOP.html" title=aop>aop="http://www.class="tags" href="/tags/SPRING.html" title=spring>springframework.org/schema/class="tags" href="/tags/AOP.html" title=aop>aop">
<class="tags" href="/tags/AOP.html" title=aop>aop:class="tags" href="/tags/SPRING.html" title=spring>spring-configured>
<bean id="annotationTransactionAspect" factory-method="aspectOf" class="org.class="tags" href="/tags/SPRING.html" title=spring>springframework.transaction.aspectj.AnnotationTransactionAspect">
<property name="transactionManager" ref="transactionManager"></property>
</bean>
<!-- the rest of your class="tags" href="/tags/APPLICATION.html" title=application>application here -->
</beans>
上面就是所有让Spring 使用Aspectj 方式@Transactional 注解事务的所有配置了。
下面我们开始把环绕事务切面的增强代码织入到注解了@Transactional 的XXService、或XXController类中(其他任何注解了@Transactional 也可以)。我们使用ant来构建织入。我们写一个ant任务来做这件事
- class="dp-xml">
- class="tag"><class="tag-name">target class="attribute">name=class="attribute-value">"compileAndWeave"class="tag">>
- class="tag"><class="tag-name">path class="attribute">id=class="attribute-value">"web-src.compile.class.path"class="tag">>
- class="comments"><!-- 指定编译时所需要的任意库, 包括AspectJ所需要的jar -->
- class="tag"><class="tag-name">path class="attribute">refid=class="attribute-value">"external.libs.path" class="tag">/>
- class="tag"></class="tag-name">pathclass="tag">>
- class="comments"><!-- 正常地编译你的源代码到这个目录中-->
- class="tag"><class="tag-name">javac class="attribute">srcdir=class="attribute-value">"src" class="attribute">destdir=class="attribute-value">"build/classes-preweave" class="attribute">classpathref=class="attribute-value">"web-src.compile.class.path" class="tag">/>
- class="comments"><!-- 查找"iajc" task -->
- class="tag"><class="tag-name">taskdef class="attribute">resource=class="attribute-value">"org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties" class="attribute">classpath=class="attribute-value">"path/to/aspectj/aspectjtools.jar"class="tag">/>
- class="comments"><!-- weave the just compiled classes from classes-preweave into classes -->
- class="tag"><class="tag-name">iajc class="attribute">inpath=class="attribute-value">"build/classes-preweave"
- class="attribute">destdir=class="attribute-value">"build/classes" class="comments"><!--正常javac编译的*.class文件,也就是我们注解了@Transactional 的XXService、或XXController类所在位置-->
- class="attribute">aspectpath=class="attribute-value">"path/to/class="tags" href="/tags/SPRING.html" title=spring>spring/class="tags" href="/tags/SPRING.html" title=spring>spring-aspects.jar" class="comments"><!--AspectJ切面类所在位置如:org.class="tags" href="/tags/SPRING.html" title=spring>springframework.transaction.aspectj.AnnotationTransactionAspect切面的位置-->
- class="attribute">classpathref=class="attribute-value">"web-src.compile.class.path"
- class="attribute">verbose=class="attribute-value">"true" class="tag">/>
- class="tag"></class="tag-name">targetclass="tag">>
class="xml" style="display: none;"><target name="compileAndWeave">
<path id="web-src.compile.class.path">
<!-- 指定编译时所需要的任意库, 包括AspectJ所需要的jar -->
<path refid="external.libs.path" />
</path>
<!-- 正常地编译你的源代码到这个目录中-->
<javac srcdir="src" destdir="build/classes-preweave" classpathref="web-src.compile.class.path" />
<!-- 查找"iajc" task -->
<taskdef resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties" classpath="path/to/aspectj/aspectjtools.jar"/>
<!-- weave the just compiled classes from classes-preweave into classes -->
<iajc inpath="build/classes-preweave"
destdir="build/classes" <!--正常javac编译的*.class文件,也就是我们注解了@Transactional 的XXService、或XXController类所在位置-->
aspectpath="path/to/class="tags" href="/tags/SPRING.html" title=spring>spring/class="tags" href="/tags/SPRING.html" title=spring>spring-aspects.jar" <!--AspectJ切面类所在位置如:org.class="tags" href="/tags/SPRING.html" title=spring>springframework.transaction.aspectj.AnnotationTransactionAspect切面的位置-->
classpathref="web-src.compile.class.path"
verbose="true" />
</target>
编译后把你的war发布到任何web容器中他就能class="tags" href="/tags/GongZuo.html" title=工作>工作了,所有注解了@Transactional 的方法(各种可见度)都能正常的处理事务,如果是类级@Transactional 注解,该类的就所有public方法都有事务。而且被注解类的内外都能调用,这样,你完全可以撇开class="tags" href="/tags/SPRING.html" title=spring>spring那麻烦的代理了,还补充一句,如果你使用了DWR做为你的ajax后台的话,服务层如果是JDK代理的话,将无法class="tags" href="/tags/GongZuo.html" title=工作>工作。只能使用Cglib方式的代理。还有很多情况,Spring 代理模式和其他一些框架配合class="tags" href="/tags/GongZuo.html" title=工作>工作的时候会有问题,全部使用AspectJ,撇开Spring 代理模式,你会觉得真的很free。