`
endual
  • 浏览: 3559523 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

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通知方式会包围事务管理拦截器执行。

下面是一个异常拦截器的例子。
有位朋友提到在spring异常拦截器中更新数据不能够提交,做了一下测试,测试环境基本是这样:一个用户登录的功能,spring对 service中的每个方法进行事务管理,在用户检测的service方法上同时加上一个异常拦截器,当用户不存在或密码不正确时用户检测方法会抛出异常,异常拦截器捕获到该异常,同时记录一些日志。
spring配置文件相关:
Java代码  收藏代码

   1. <span style="font-size: medium;">   <!-- 事务管理 --> 
   2.     <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">  
   3.         <property name="sessionFactory" ref="sessionFactory"></property> 
   4.     </bean> 
   5.      
   6.     <!-- 事务通知 --> 
   7.     <tx:advice id="txAdvice" transaction-manager="transactionManager"> 
   8.         <tx:attributes> 
   9.             <tx:method name="get*" read-only="true"/> 
  10.             <tx:method name="*" propagation="REQUIRES_NEW" rollback-for="Exception"/> 
  11.         </tx:attributes> 
  12.     </tx:advice> 
  13.      
  14.     <!-- aop代理设置 --> 
  15.     <aop:config proxy-target-class="true"> 
  16.         <aop:pointcut id="txPointcut" expression="execution(* com.hbs..*Service.*(..))"/> 
  17.         <aop:pointcut id="logPointcut" expression="execution(* com.hbs.customer..*Service.*(..))"/> 
  18.         <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" order="1"/> 
  19.         <aop:aspect id="logAspect" ref="logInterceptor" order="2" > 
  20.             <aop:after-throwing 
  21.                 pointcut-ref="logPointcut"  
  22.                 method="serviceIntercept" /> 
  23.         </aop:aspect> 
  24.     </aop:config> 
  25.      
  26.     <!-- log拦截器类 --> 
  27.     <bean id="logInterceptor" class="com.hbs.eventlog.EventLogInterceptor"> 
  28.         <property name="service" ref="logService"></property> 
  29.     </bean>   </span> 

<!-- 事务管理 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>

<!-- 事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="*" propagation="REQUIRES_NEW" rollback-for="Exception"/>
</tx:attributes>
</tx:advice>

<!-- aop代理设置 -->
<aop:config proxy-target-class="true">
<aop:pointcut id="txPointcut" expression="execution(* com.hbs..*Service.*(..))"/>
<aop:pointcut id="logPointcut" expression="execution(* com.hbs.customer..*Service.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" order="1"/>
<aop:aspect id="logAspect" ref="logInterceptor" order="2" >
<aop:after-throwing
pointcut-ref="logPointcut"
method="serviceIntercept" />
</aop:aspect>
</aop:config>

<!-- log拦截器类 -->
<bean id="logInterceptor" class="com.hbs.eventlog.EventLogInterceptor">
<property name="service" ref="logService"></property>
</bean>





拦截器类:
Java代码  收藏代码

   1. <span style="font-size: medium;">public class EventLogInterceptor implements Ordered { 
   2.  
   3.     private int order = 1; 
   4.      
   5.     private EventLogService service; 
   6.      
   7.     public Object serviceIntercept(ProceedingJoinPoint point) throws Throwable{ 
   8.         if(point instanceof MethodInvocationProceedingJoinPoint){ 
   9.             MethodInvocationProceedingJoinPoint mpoint = (MethodInvocationProceedingJoinPoint)point; 
  10.             // 
  11.         } 
  12.         try {  
  13.             System.out.println("记录日志开始"); 
  14.             service.eventLog(); 
  15.             System.out.println("记录日志结束"); 
  16.         }catch(Exception ex) { 
  17.             ex.printStackTrace(); 
  18.         } 
  19.         return null; 
  20.     } 
  21.      
  22.     public void setOrder(int order){ 
  23.         this.order = order; 
  24.     } 
  25.     public int getOrder() { 
  26.         return order; 
  27.     } 
  28.     public EventLogService getService() { 
  29.         return service; 
  30.     } 
  31.     public void setService(EventLogService service) { 
  32.         this.service = service; 
  33.     } 
  34. } 
  35. </span> 

public class EventLogInterceptor implements Ordered {

private int order = 1;

private EventLogService service;

public Object serviceIntercept(ProceedingJoinPoint point) throws Throwable{
if(point instanceof MethodInvocationProceedingJoinPoint){
MethodInvocationProceedingJoinPoint mpoint = (MethodInvocationProceedingJoinPoint)point;
//
}
try {
System.out.println("记录日志开始");
        service.eventLog();
        System.out.println("记录日志结束");
        }catch(Exception ex) {
            ex.printStackTrace();
        }
        return null;
}

public void setOrder(int order){
this.order = order;
}
public int getOrder() {
return order;
}
public EventLogService getService() {
return service;
}
public void setService(EventLogService service) {
this.service = service;
}
}




service方法中的事务传播属性都设为要求新建事务,spring事务管理切面拦截器的order设为1,而log拦截器的order设为2,这意味着这两个要同时执行时,先执行事务拦截器,后执行log拦截器,由于事务管理是一个环绕通知(around),实际上是log拦截器被包围在事务管理拦截器中。

从中可以看出,log异常拦截器在用户登录的事务回滚之前截获异常,在记录日志时,日志记录的service方法也在spring的事务管理之下,用户登录的事务还没有结束,根据REQUIRES_NEW特性,spring会新开一个事务,这时原来的数据库连接已经在一个事务中,一个连接不可能同时有两个事务,所以同时新创建一个session连接(虽然我使用了OpenSessionInViewFilter,并且session是单例的),日志记录就在新建的事务和session中进行,完了提交,并且会把新建的session连接关闭。
然后继续进行被中断的用户登录的事务管理操作,由于抛异常spring将用户登录的事务回滚。
这样能够实现预想的功能,但是如果我去掉指定的REQUIRES_NEW,那么log记录的操作会继续在用户登录的事务中进行,最后会被一起回滚。

如果把事务管理的order设为2,log拦截器的order设为1,也就是log拦截器在事务管理拦截器的外面,会在事务管理拦截器前后执行完了再执行log的异常拦截器。

可以看出,用户登录的事务和日志记录的事务是前后两个不相关的事务,并且在日志记录事务中并不需要新建session连接,而是直接用在 OpenSessionInViewFilter中创建的session。实际上这时也并不需要将propagation设为REQUIRES_NEW,使用默认的REQUIRES也照样能够正常工作。

所以应该将该异常拦截器设在事务管理拦截器的外面,即使用Order接口排在前面。
(本文章转载来自http://endual.iteye.com/admin/blogs/new)。博客作者改编了题目
分享到:
评论

相关推荐

    spring AOP注解的应用1

    在Spring框架中,AOP(面向切面编程)是一种强大的工具,它允许程序员将关注点分离,例如日志记录、事务管理、权限检查等,从核心业务逻辑中解耦出来。本篇主要探讨的是如何利用Spring AOP的注解来实现这些功能,...

    spring的aop切面编程实例

    AOP提供了一种模块化系统的方式,将关注点分离为独立的“切面”,这些切面可以包含业务逻辑的多个方面,如日志、事务管理、性能监控等。切点(Pointcut)定义了这些关注点插入到代码中的位置,而通知(Advice)则...

    Spring系列面试题129道(附答案解析)

    在Spring AOP中,concern指的是应用程序中的业务逻辑代码,而cross-cutting concern是横切关注点,如日志记录、事务管理等,这些关注点贯穿多个业务逻辑。 44、AOP有哪些实现方式? AOP可以通过以下几种方式实现: ...

    665.663.JAVA基础教程_动态代理与Java8新特性-AOP与动态代理的举例(665).rar

    这种代理类可以拦截调用,并在调用前后执行额外的操作,如日志记录、事务管理等。Java的`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口是实现动态代理的核心组件。 2. 创建动态代理 要...

    开源框架面试题系列:Spring+SpringMVC+MyBatis

    2. **AOP**:阐述AOP的概念,介绍通知类型(前置、后置、环绕、异常和最终通知),并举例说明如何实现日志记录或事务管理。 3. **Spring MVC**:Spring MVC是Spring框架的一部分,用于构建Web应用。讨论...

    SSH框架面试题.rar

    2. **面向切面编程(AOP)**:Spring提供AOP支持,实现事务管理、日志记录等功能。 3. **容器**:Bean工厂和ApplicationContext是Spring的两大容器,负责管理Bean的生命周期。 4. **Spring MVC**:Spring的MVC模块,...

    ssm简单事例

    Spring是核心的依赖注入(DI)和面向切面编程(AOP)框架,它管理着应用中的对象及其依赖关系,提供了事务管理、数据源配置等功能。在本示例中,Spring将作为整个框架的基础,负责配置、管理其他组件以及业务逻辑。 ...

    SSM框架例子

    Spring的AOP功能则允许开发者定义切面,实现如日志记录、事务管理等通用功能,无需在业务代码中重复编写。 SpringMVC作为Spring的Web MVC模块,负责接收HTTP请求,调度控制器,处理视图以及与模型的交互。它提供了...

    动态代理例子

    这通常用于实现AOP(面向切面编程)的概念,如日志、事务管理、性能监控等。下面将详细讲解动态代理的原理、实现方式以及如何通过反射来创建动态代理。 首先,了解动态代理的基本概念。在Java中,动态代理基于JDK的...

    SSM框架详细整合教程

    - **spring-mybatis.xml**:配置Spring与MyBatis的整合,包括数据源、事务管理器、SqlSessionFactory等。 - **spring-mvc.xml**:配置SpringMVC,包括视图解析器、拦截器等。 ##### 3.3 数据库连接配置 (`jdbc....

    ssh整合举例

    Spring的依赖注入(DI)和面向切面编程(AOP)特性使得代码更加解耦,易于测试和维护。在SSH整合中,Spring主要负责业务逻辑的协调和数据访问的管理。 2. Struts框架: Struts是MVC(Model-View-Controller)设计...

    phillips_spring_examples:举例说明如何使用Spring功能的应用程序

    AOP是Spring提供的一种处理横切关注点(如日志、事务管理)的技术。在项目中,可能包含自定义的切面,通过定义通知(advice)和切入点(pointcut),实现代码的解耦,使得业务逻辑更加清晰。 4. **数据访问** ...

    一个简单的java动态代理的实例

    这在处理如日志、事务管理、性能监控等跨切面关注点时非常有用。 `Proxy`类是Java动态代理的工厂,它提供了`newProxyInstance()`方法,用于创建代理对象。这个方法需要三个参数:目标接口的类加载器、目标接口数组...

    简单的框架组成的MVC实例

    Spring是一个全面的企业级应用开发框架,它提供了依赖注入(DI)、面向切面编程(AOP)、事务管理、数据访问/集成、MVC等核心功能。在MVC模式中,Spring MVC作为控制器,负责调度请求,并与模型和视图进行交互。...

    SSH三大框架所有的配置文件详解

    - `applicationContext.xml`:这个文件通常包含更广泛的应用范围的配置,比如数据源、事务管理、DAO和Service层的Bean定义。 4. **集成配置**: - 在SSH集成项目中,通常还需要一个或多个额外的配置文件来协调这...

    java面试题题宝典.zip

    - MyBatis:SQL映射、动态SQL、事务管理。 - Hibernate:对象关系映射、缓存机制。 - Struts:MVC架构、Action类、拦截器。 3. **中间件**: - 消息队列:RabbitMQ、Kafka、ActiveMQ,如何实现异步处理和解耦。...

    java面试题

    - **封装、继承和多态**:理解这三个面向对象的基本特性,并能举例说明。 - **构造器**:了解构造函数的作用,构造器的重载和实例化过程。 - **访问修饰符**:private, protected, public, default的使用场景及其...

    黑马面试宝典知识点复习

    - **面向切面编程**:利用AOP实现日志记录、事务管理等功能。 - **声明式事务管理**:简化事务管理的配置和使用。 #### SpringMVC框架 - **请求处理**:使用@Controller注解定义控制器类,@RequestMapping注解映射...

    shouhu 面试 java 比较全的题目.docx

    - **AOP**:介绍切面编程的基本概念,以及如何实现方法拦截。 以上这些知识点是Java开发人员必须掌握的基础内容,同时也是SOHU等公司面试时可能会涉及的重要领域。准备这些题目有助于提升Java程序员的技术深度和...

Global site tag (gtag.js) - Google Analytics