`

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配置文件相关:

 

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

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接口排在前面。

分享到:
评论

相关推荐

    spring aop日志拦截

    当controller中的方法被调用时,日志拦截器将会自动记录方法的调用和结束,提供详细的运行信息。这种方法使得我们可以将日志处理代码与业务逻辑分离,提高了代码的可读性和可维护性。 总结来说,Spring AOP为我们...

    ssh+aop+log4j+日志拦截器+注解

    标题中的"ssh+aop+log4j+日志拦截器+注解"涉及到的是Java Web开发中的几个核心组件和技术,这些技术在构建大型、分布式的企业级应用时常常被使用。下面将详细介绍这些知识点: 1. SSH (Spring, Struts, Hibernate)...

    mybatis 拦截器 + spring aop切面 + spring事务+ 反射工具类

    例如,可能会有一个自定义的MyBatis拦截器用于分页查询,一个Spring AOP切面用于记录操作日志,Spring事务管理确保数据的一致性,而反射工具类可能用于动态加载配置或处理某些通用的反射任务。通过这些组件的组合,...

    spring aop 拦截器简单实现

    首先,AOP的主要目标是解决程序中的横切关注点,如日志记录、事务管理、性能监控等。这些关注点通常与业务逻辑交织在一起,但又不属于业务逻辑本身。AOP通过将这些关注点分离出来,使代码更易于维护和扩展。 在...

    详解Spring AOP 拦截器的基本实现

    AOP(面向切面编程)是一种编程范式,旨在将横切关注点(如日志、安全、事务管理等)从业务逻辑中分离出来,以提高模块化。通过AOP可以在不改变源代码的情况下添加额外的行为,这通常称为“横切”。AOP是OOP(面向对象...

    Spring AOP 拦截器 Advisor

    在 Spring 中,AOP 主要用于日志记录、事务管理、安全性检查等跨功能需求。拦截器是 AOP 的一种实现方式,它在方法调用前、后或异常发生时执行自定义逻辑。 Advisor 在 Spring AOP 中扮演了中介的角色。它包含两...

    spring aop 拦截日志示例

    在Spring AOP(面向切面编程)中,我们可以通过定义拦截器来实现对系统操作日志和异常日志的记录,这些日志信息通常会被存储到数据库中以便于后续的分析和故障排查。下面将详细介绍如何使用Spring AOP实现这个功能。...

    spring aop 拦截实例

    1. **切面(Aspect)**:切面是AOP中的核心概念,它封装了系统中的横切关注点,如日志记录、事务管理。在Spring中,一个切面可以是一个Java类,通过使用`@Aspect`注解来标识。 2. **通知(Advice)**:通知是在特定...

    spring_aop_拦截实例

    在Spring框架中,AOP(面向切面编程)是一种强大的工具,它允许程序员定义横切关注点,如日志、事务管理、性能监控等,并将它们模块化为可重用的组件,称为切面。本实例主要探讨如何在Spring AOP中实现拦截器。 ...

    Spring aop 性能监控器

    在IT行业中,Spring AOP(面向切面编程)是一种强大的工具,它允许我们在不修改代码的情况下,对应用程序的特定部分进行拦截和增强。这在性能监控、日志记录、事务管理等方面尤为有用。本篇文章将深入探讨如何使用...

    Spring使用AOP的三个jar包

    AOP是一种编程范式,它允许程序员定义“切面”,这些切面可以封装关注点,如日志、事务管理、性能监控等,与业务逻辑解耦。要使用Spring的AOP功能,我们需要引入特定的库,这正是标题中提到的"Spring使用AOP的三个...

    SpringAOP原理及拦截器.pdf

    面向切面编程(AOP,Aspect Oriented Programming)是一种编程范式,旨在将关注点分离,使得核心...它通过AOP代理和拦截器机制实现了对目标对象的透明增强,为诸如事务管理、日志记录等功能的实现提供了便捷的方式。

    在自定义spring aop中使用el获取拦截方法的变量值。

    Spring AOP是Spring框架的一个重要特性,它允许开发者创建具有横切关注点的模块,如日志记录、事务管理等。这些关注点可以被声明性地应用到多个对象上,而无需修改这些对象的代码。Spring AOP通过动态代理实现,有两...

    Spring AOP四种创建通知(拦截器)类型

    Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架中的一个重要模块,它提供了在应用代码中添加横切关注点的能力,如日志记录、事务管理、权限验证等,而无需显式修改业务逻辑代码。本文将深入...

    spring AOP拦截方法小示例

    在Spring框架中,AOP(面向切面编程)是一种强大的设计模式,用于处理系统中的横切关注点,如日志记录、事务管理、性能监控等。这个“spring AOP拦截方法小示例”是一个实际应用,展示了如何使用Spring AOP来拦截...

    SpringAOP原理及拦截器.doc

    Spring AOP,全称为Spring的面向切面编程,是一种编程范式,旨在将核心业务逻辑与横切关注点(如事务管理、日志记录、安全控制等)分离,以提高代码的可重用性和可维护性。AOP是基于IoC(Inversion of Control,控制...

    Spring Boot Aspect 切面 AOP 拦截器 Interceptor 监控control请求耗时

    在Spring Boot应用中,面向切面编程(AOP)是一种强大的设计模式,它允许我们以声明式的方式插入代码,比如日志记录、事务管理或权限检查。Aspect是AOP的核心概念,它封装了关注点,使得我们可以将这些关注点与业务...

    Spring Aop四个依赖的Jar包

    这样,业务代码和关注点(如日志、事务管理等)得以分离,提高了代码的可读性和可维护性。 要使用Spring AOP,通常需要引入以下几个核心的Jar包: 1. **aspectj-1.7.3.jar**:这是AspectJ库的核心部分,提供了AOP...

    Spring AOP IOC源码笔记.pdf

    此外,AOP机制则提供了在不修改业务代码的情况下,插入横切关注点(如日志、事务管理)的能力。 2. 控制反转(IoC): IoC的核心思想是将对象的创建和管理职责从应用程序转移到框架中。在Spring中,这通过...

    spring aop demo 两种实现方式

    在Spring中,我们可以使用`@Aspect`注解来定义一个切面,这个切面包含了多个通知(advice),即拦截器。例如: ```java @Aspect @Component public class LoggingAspect { @Before("execution(* ...

Global site tag (gtag.js) - Google Analytics