今 天在开发过程中发现一个很奇怪的问题,在模拟事务回滚过程中,发现事务回滚没问题,异常也输出了,但之前配置的afterthrowing记录出错日志配 置却始终不好用,根本不会执行到afterthrowing配置的方法内但afterreturning配置 却没有问题,去掉配置的AOP事务后,afterthrowing一切正常。。。仔细想想整个程序执行步骤,考虑到事务的回滚用到的是环绕通知 around,是不是两个同时执行,log拦截器包含在了事务拦截器里,所以当事务遇到了错误回滚也直接将插入异常日志一同回滚了?能不能在事务执行遇到 exception回滚以后再去控制它去进入afterthowing配置的方法?于是我又仔细看了看spring 关于aop的配置,惊喜的发现一个"order"参数,这个参数是用来控制aop通知的优先级,值越小,优先级越高,于是我手动设置了事务与异常日志两个 aop通知的order 参数,控制log拦截器在事务的around之外,不出我所料,问题最终得到解决~~
以下是部分代码,可供参考:
<!-- AOP 事务 -->
<aop:config>
<aop:pointcut id="serviceMethods"
expression="execution(* hamob.*.*(..))" />
<aop:advisor advice-ref="txAdvice"
pointcut-ref="serviceMethods" order="2"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" isolation="READ_COMMITTED"/>
<tx:method name="add*" propagation="REQUIRED" isolation="READ_COMMITTED"/>
<tx:method name="update*" propagation="REQUIRED" isolation="READ_COMMITTED"/>
<tx:method name="delete*" propagation="REQUIRED" isolation="READ_COMMITTED"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- AOP 日志管理 -->
<aop:config>
<aop:aspect ref="logadvice" order="3">
<aop:pointcut id="logInsertMethods" expression="execution(* hamob.*.save*(..))"/>
<aop:after-returning method="saveLog" pointcut-ref="logInsertMethods" returning="rvt"/>
</aop:aspect>
</aop:config>
<!-- AOP throwing管理 -->
<aop:config>
<aop:aspect ref="logadvice" order="1">
<aop:pointcut id="throwinglog" expression="execution(* hamob.*.save*(..))"/>
<aop:after-throwing pointcut-ref="throwinglog" throwing="throwable" method="afterThrowing"/>
</aop:aspect>
</aop:config>
在我的程序中,由于用到了hibernate,因此事务注解分布在各处,结果发现after-throwing无法抓取异常(在指定包名后)。在一个数据库操作抛出异常后,事务管理器采取了回滚策略,导致程序抛出异常后,回滚到事务管理器的处理中,指定包名后更加抓取不到异常了。
<aop:config>
<aop:aspect ref="exceptionCacher" order="0">
<aop:pointcut id="performance2" expression="execution(* com.ebupt.justholdon.server..*.*(..))" />
<aop:after-throwing pointcut-ref="performance2" method="throwExp" throwing="exp"/>
</aop:aspect>
</aop:config>