关于Spring中AOP的几种拦截方式

探讨一下spring拦截器中的数据库操作和事务管理。 
大家知道spring中的事务管理是通过AOP代理来实现的,对被代理对象的每个方法进行拦截,在方法执行前启动事务,方法执行完后根据是否有异常和异常的种类进行提交或回滚。 

如果要在方法执行前或后或抛出异常后加上一个自己的拦截器,或者一个环绕拦截器,在拦截器中执行一些操作,比如执行一些数据库操作,记录一些信息,这些操作通过调用一个服务类的方法来执行,这个方法也在spring事务管理拦截器的管理之下,那么这个记录方法需要在另一个事务中进行,而不是与被拦截方法在同一个事务中,不然如果被拦截方法抛出异常需要回滚时,所作的记录也会被回滚,当然有时候确实需要同时回滚,那就要放在同一个事务中。 

这和自己的拦截器和事务管理的拦截器的执行顺序有一定关系,spring事务管理拦截器是一个环绕通知,在被拦截方法执行前启动事务,执行后完成事务,如果自己的拦截器被spring事务管理拦截器包围在里面,那么在自己的拦截器运行时,spring已经启动了一个事务,如果你的记录信息方法需要与被拦截方法同在一个事务中,将你的记录信息方法的事务传播属性设为默认的REQUIRED就可以了; 
如果你记录信息的方法需要单独的一个事务环境,那就要把事务传播属性设为REQUIRES_NEW了,这样spring事务管理器会新建一个事务,并且新建一个session连接,因为一个数据库连接不可能同时有两个事务,记录信息完了提交事务并且把新建的session连接关闭,自己的拦截器退出后继续执行被拦截的方法或它的事务处理。 

相反如果自己的拦截器在spring事务管理拦截器的外面,那么记录信息的方法会在一个单独的事务中执行,并提交,不管它的事务传播属性是REQUIRES_NEW还是REQUIRED,因为与被拦截方法的事务处理没有交叉,并且可以使用同一个session连接如果是OpenSessionInViewFilter。 

所以如果记录信息和被拦截方法要在不同事务中执行,分别提交,那么最好将自己的拦截器设在spring事务管理器拦截器的外面;如果需要将记录信息和被拦截方法在同一个事务中处理,必须将自己的拦截器被包围在spring事务管理拦截器中,并且记录信息方法的事务传播属性为默认的REQUIRED。 


设置拦截器的执行顺序可以让拦截器处理类实现org.springframework.core.Ordered接口,在spring配置文件的AOP设置中设定自己的拦截器和spring事务管理拦截器的执行顺序,将自己的拦截的序号排在spring事务管理的前面,就可以将该拦截器放到事务管理拦截器的外面执行了,对于before通知方式会先于事务管理拦截器执行,对于after returning和after和after throwing通知方式会后于事务管理拦截器的执行,对于arount通知方式会包围事务管理拦截器执行。 

今天所引用的是老师所讲的关于User的例子

在此给出一个类,在这个类中锁写的四个方法

public class AopAspect {
//表示在方法执行之后拦截
       public void doAfter(JoinPoint jp){
      System.out.println("拦截方法"+jp.getTarget().getClass().getName()+"."+jp.getSignature().getName());
       }
       //在方法之前拦截
       public void doBefore(JoinPoint jp){
      System.out.println("拦截方法"+jp.getTarget().getClass().getName()+"."+jp.getSignature().getName());
       }
       //在方法抛出异常是拦截
       public void doException(JoinPoint jp,Throwable e) throws Exception{
     
      
      System.out.println("拦截方法"+jp.getTarget().getClass().getName()+"."+jp.getSignature().getName());
      System.out.println(e.getMessage());
       }
       
       public void doAfer(JoinPoint jp){
      System.out.println("拦截方法"+jp.getTarget().getClass().getName()+"."+jp.getSignature().getName());
       }
}

以及在bean2.xml中的相应的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans default-autowire="byName"
default-lazy-init="true"
xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="log" class="aop.AopAspect"></bean>
<!-- 配置两个切入点 -->
<aop:config >
<!-- 把log植入,把代理类置入 -->
  <aop:aspect ref="log">
  <!-- 定义切入点 -->
  <!-- aop包下的所有以add开头的方法 -->
   <aop:pointcut expression="execution(* aop.*Dao*.*(..))" id="addMethod"/>
  <!-- <aop:before method="doBefore" pointcut-ref="addMethod"/>  -->
<!-- <aop:after method="doAfter" pointcut-ref="addMethod"/> -->
<aop:after-throwing method="doException" pointcut-ref="addMethod"/>
   <!-- <aop:after-returning method="doAfer" pointcut-ref="addMethod"/> -->
  </aop:aspect>
  
</aop:config>

<bean id="userDao" class="aop.UserDaoImpl" scope="singleton"></bean>
        <bean id="usermanager" class="aop.UserManager" scope="singleton"> 
        <property name="userdao" ref="userDao"></property>
        </bean>

</beans>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值