`

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

	<!-- 事务管理 -->
	<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>	





 拦截器类:

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://www.iteye.com/topic/71030

分享到:
评论

相关推荐

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

    内含有mybatis 拦截器实现的分页代码,spring 的事务和aop 测试、和反射工具类

    深入理解Spring声明式事务:源码分析与应用实践

    在Spring中,事务管理是通过一系列的拦截器和事务管理器来实现的。当一个被@Transactional注解的方法被调用时,Spring会创建一个代理来包装该方法,确保事务的正确开始和结束。这种代理机制基于Spring AOP实现,能够...

    spring源码分析(1-10)

    Spring源代码解析(七):Spring AOP中对拦截器调用的实现 Spring源代码解析(八):Spring驱动Hibernate的实现 Spring源代码解析(九):Spring Acegi框架鉴权的实现 Spring源代码解析(十):Spring Acegi框架授权...

    spring事务管理几种方式代码实例

    spring事务管理几种方式代码实例:涉及编程式事务,声明式事务之拦截器代理方式、AOP切面通知方式、AspectJ注解方式,通过不同方式实例代码展现,总结spring事务管理的一般规律,从宏观上加深理解spring事务管理特性...

    Spring开发指南

    XWork 拦截器体系 输入校验 国际化支持 Webwork2 in Spring Struts in Spring 数据持久层 事务管理 持久层封装 JDBC Hibernate in Spring ibatis in Spring Aspect Oriented Programming AOP 概念 ...

    Spring源代码解析

    Spring源代码解析(七):Spring AOP中对拦截器调用的实现 Spring源代码解析(八):Spring驱动Hibernate的实现 Spring源代码解析(九):Spring Acegi框架鉴权的实现 Spring源代码解析(十):Spring Acegi框架授权...

    spring源码分析

    Spring源代码解析(七):Spring AOP中对拦截器调用的实现 8. Spring源代码解析(八):Spring驱动Hibernate的实现 9.Spring源代码解析(九):Spring Acegi框架鉴权的实现 10. Spring源代码解析(十):Spring ...

    Spring源码学习文档,绝对值得好好研究~~

    Spring源代码解析(七):Spring AOP中对拦截器调用的实现.doc Spring源代码解析(八):Spring驱动Hibernate的实现.doc Spring源代码解析(九):Spring Acegi框架鉴权的实现.doc Spring源代码解析(十):Spring ...

    Spring源代码解析.rar

    Spring源代码解析7:Spring AOP中对拦截器调用的实现 .doc Spring源代码解析8:Spring驱动Hibernate的实现.doc Spring源代码解析9:Spring Acegi框架鉴权的实现.doc Spring源代码解析10:Spring Acegi框架授权的实现...

    使用Spring更好地处理Struts动作

    用,留给您的简单任务就只是在一个 XML 配置文件中把它们连接好。 依赖注入是一个强大的特性,但是 Spring ...您很快就会看到,为了处理横切关注点,Spring AOP 发布了它自己的拦截器,您也可以编写您自己的拦截器。

    基于SSM框架(SpringMVC + Spring + Mybatis)的图书管理系统数据库.rar

    此系统采用了目前最流行的ssm框架,其中的spingMVC框架相对于struts2框架更灵活,更安全。... 3 同时使用了了hibernate提供的校验框架,对客户端数据... 5 spring容器内部使用拦截器,以Spring AOP的方式实现事务控制管理。

    Spring 源代码解析

    Spring源代码解析7:Spring AOP中对拦截器调用的实现 Spring源代码解析8:Spring驱动Hibernate的实现;Spring源代码解析9:Spring Acegi框架鉴权的实现 Spring源代码解析10:Spring Acegi框架授权的实现

    Java八股文-Spring AOP

    通知是直译过来的结果,我个人感觉叫做“业务增强”更合适 对照代码就是拦截器定义的 相关方法,通知分为如下几种: 1. 前置通知(before):在执行业务代码前做些操作,比如获取连接对象,登陆鉴权 2. 后置通知(after)...

    基于SSM框架(SpringMVC + Spring + Mybatis)的图书管理系统,内附,教程,数据库脚本

    1 此系统采用了目前最流行的ssm框架,其中的spingMVC框架相对于struts2框架更灵活,更安全。 ... 3 同时使用了了hibernate提供的校验框架,对客户端...5 spring容器内部使用拦截器,以Spring AOP的方式实现事务控制管理。

    Spring + Hibernate + Struts 事务配置小例子(带提示框等小技巧)

    -- 事务拦截器bean需要依赖注入一个事务管理器 --&gt; &lt;!-- 下面定义事务传播属性 [ bus* 事务的方法名]--&gt; *"&gt;PROPAGATION_REQUIRED &lt;!-- 定义BeanNameAutoProxyCreator,该bean是个bean后...

    JavaSpring的商城项目前台+后台+api

    面向切面编程(AOP):Spring支持AOP,允许定义方法拦截器和切点来分离应用程序的业务逻辑和系统服务。这有助于增加模块化,并且可以用于事务管理、日志记录等。 事务管理:Spring提供了一致的事务管理接口,可以在...

    Spring-Reference_zh_CN(Spring中文参考手册)

    13.4.3. 拦截器(HandlerInterceptor) 13.5. 视图与视图解析 13.5.1. 视图解析器 13.5.2. 视图解析链 13.5.3. 重定向(Rediret)到另一个视图 13.5.3.1. RedirectView 13.5.3.2. redirect:前缀 13.5.3.3. forward:...

    spring.net中文手册在线版

    14.5.1.理解Spring.NET声明式事务管理的实现 14.5.2.第一个例子 14.5.3.Transaction特性的设置 14.5.4.通过AutoProxyCreator使用声明式事务 14.5.5.通过TransactionProxyFactoryObject使用声明式事务 14.5.6. 通过...

    Spring中文帮助文档

    13.4.3. 拦截器(HandlerInterceptor) 13.5. 视图与视图解析 13.5.1. 视图解析器(ViewResolver) 13.5.2. 视图解析链 13.5.3. 重定向(Rediret)到另一个视图 13.6. 本地化解析器 13.6.1. ...

Global site tag (gtag.js) - Google Analytics