`
tom.duan
  • 浏览: 43416 次
  • 性别: Icon_minigender_1
  • 来自: 珠海
文章分类
社区版块
存档分类
最新评论

Spring的事务通知

阅读更多
Spring 1.x文档中说:在Spring声明式事务管理中,可以通过TransacationProxyFactoryBean的preInterceptors和postInterceptors属性设置“前”或“后”通知来提供额外的拦截行为,并可以设置任意数量的“前”“后”通知,他们的类型可以使Advisor、MethodInterceptor或则被当前Spring配置所支持的通知类型,如BeforeAdvice和AfterReturningAdvice等等。

看到这里有一些疑惑,在事务声明中,如果一个事务代理设置给preInterceptors属性一个通知,按照Spring文档中的理解,这个通知将在事务方法开始前进行通知,反之亦然。但是如果给preInterceptors设置一个实现了AfterReturningAdvice接口的通知呢?执行结果会如何,通知在方法执行前还是后呢?为了解惑,写了一个小例子,来真实的模拟一下事务中通知是如何运作的,Spring版本1.2.6。

首先,一个简单的service及实现
MyService.java
package com.ccb.tra;

public interface MyService {
	public void getAll();
}

MyServiceImpl.java
package com.ccb.tra;

public class MyServiceImpl implements MyService{

	public void getAll() {
		try {
			System.out.println("getAll Method........");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}


为了更真实的观察,这里建立三个类型的通知,分别实现MethodBeforeAdvice、MethodInterceptor、AfterReturningAdvice接口
MyBeforeAdvice.java
package com.ccb.tra;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

public class MyBeforeAdvice implements MethodBeforeAdvice {
	public void before(Method method, Object[] object, Object object0) throws Throwable {
		System.out.println("MethodBeforeAdvice.............");
	}
}


MyInterceptor.java
package com.ccb.tra;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class MyInterceptor implements MethodInterceptor
{
	public Object invoke(MethodInvocation invocation) throws Throwable {
		System.out.println("MethodInterceptor.................");
		return invocation.proceed();
	}
}


MyAfterAdvice.java
package com.ccb.tra;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;

public class MyAfterAdvice implements AfterReturningAdvice {
	public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws 

Throwable {
		System.out.println("AfterReturningAdvice.............");
	}
}


可以看到在每个通知被使用时,将会在控制台打印一条信息。三个通知所实现的接口的作用不再过多的描述,用法请参考Spring开发文档.

然后,写Spring配置文件.
tra.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
	"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-

method="close">
		<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
		<property name="url" value="jdbc:oracle:thin:@192.168.1.110:1521:xmldb" />
		<property name="username" value="neohkdev1" />
		<property name="password" value="xml" />
		<property name="initialSize" value="5"/>
		<property name="maxActive" value="5"/>
	</bean>
	<!-- service target -->
	<bean id="myServiceTarget" class="com.ccb.tra.MyServiceImpl"/>
	
	<!-- before -->
	<bean id="myBeforeAdvice" class="com.ccb.tra.MyBeforeAdvice"/>
	<!-- Interceptor -->
	<bean id="myInterceptor" class="com.ccb.tra.MyInterceptor"/>
	<!-- myAfterAdvice -->
	<bean id="myAfterAdvice" class="com.ccb.tra.MyAfterAdvice"/>
	
	<bean id="traManager" 

class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource">
			<ref local="dataSource"/>
		</property>
	</bean>
	
	<bean id="myService" 

class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
		<property name="transactionManager">
			<ref bean="traManager"/>
		</property>
		<property name="target">
			<ref bean="myServiceTarget"/>
		</property>
		<!-- preInterceptors属性,包含三个通知 -->
		<property name="preInterceptors">
			<list>
				<ref bean="myBeforeAdvice"/>
				<ref bean="myInterceptor"/>
				<ref bean="myAfterAdvice"/>
			</list>
		</property>
		<property name="transactionAttributes">
			<props>
				<prop key="get*">PROPAGATION_REQUIRED</prop>
			</props>
		</property>
	</bean>
</beans>

配置文件中可以看到为Service定义了一个简单的事务,并定义了三个通知,并将这些通知注入到TransactionProxyFactoryBean的preInterceptors属性中,按照spring对preInterceptors属性的描述来看,这三个通知都将在service方法执行前执行。

写一个简单的测试类测试一下他们的执行结果
Main.java
package com.ccb.tra;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
	public static void main(String[] args) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("tra.xml");
		
		MyService myService = (MyService)ctx.getBean("myService");
		myService.getAll();
	}
}


好了,运行Main.java看下执行结果
MethodBeforeAdvice.............

MethodInterceptor.................

getAll Method........

AfterReturningAdvice.............

貌似结果不对,AfterReturningAdvice通知竟然在service方法执行后才执行,怪异,和Spring所描述的preInterceptors属性的作用不符,但是和AOP中描述的通知接口的作用一致,察看TransactionProxyFactoryBean源码发现了对这两个属性定义的操作方式,

public void afterPropertiesSet() {
		this.transactionInterceptor.afterPropertiesSet();

		if (this.target == null) {
			throw new IllegalArgumentException("'target' is required");
		}
		if (this.target instanceof String) {
			throw new IllegalArgumentException("'target' needs to be a bean 

reference, not a bean name as value");
		}

		ProxyFactory proxyFactory = new ProxyFactory();

		//preInterceptors属性
		if (this.preInterceptors != null) {
			for (int i = 0; i < this.preInterceptors.length; i++) {
				//请注意这一句代码
				proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap

(this.preInterceptors[i]));
			}
		}

		if (this.pointcut != null) {
			Advisor advice = new DefaultPointcutAdvisor(this.pointcut, 

this.transactionInterceptor);
			proxyFactory.addAdvisor(advice);
		}
		else {
			// Rely on default pointcut.
			proxyFactory.addAdvisor(new TransactionAttributeSourceAdvisor

(this.transactionInterceptor));
			// Could just do the following, but it's usually less efficient because 

of AOP advice chain caching.
			// proxyFactory.addAdvice(transactionInterceptor);
		}
		//postInterceptors属性

		if (this.postInterceptors != null) {
			for (int i = 0; i < this.postInterceptors.length; i++) {
				//请注意这一句代码
				proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap

(this.postInterceptors[i]));
			}
		}

		proxyFactory.copyFrom(this);

		TargetSource targetSource = createTargetSource(this.target);
		proxyFactory.setTargetSource(targetSource);

		if (this.proxyInterfaces != null) {
			proxyFactory.setInterfaces(this.proxyInterfaces);
		}
		else if (!isProxyTargetClass()) {
			// Rely on AOP infrastructure to tell us what interfaces to proxy.
			proxyFactory.setInterfaces(ClassUtils.getAllInterfacesForClass

(targetSource.getTargetClass()));
		}
		
		this.proxy = getProxy(proxyFactory);
	}

上面的一段代码的作用我的理解是将preInterceptors和postInterceptors中所包含的通知注入到proxyFactory.

通知在注入到proxyFactory后,由proxyFactory负责管理通知,这个我想和普通AOP的通知管理是一样的,按照通知所实现的接口来判断通知的调用顺序,而TransactionProxyFactoryBean将这些通知交给proxyFactory后就撒手不管了,而且在进行处理preInterceptors和postInterceptors所包含的通知时没有任何的区别.
处理preInterceptors
if (this.preInterceptors != null) {
			for (int i = 0; i < this.preInterceptors.length; i++) {
				proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap

(this.preInterceptors[i]));
			}
		}


处理postInterceptors
if (this.postInterceptors != null) {
			for (int i = 0; i < this.postInterceptors.length; i++) {
				proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap

(this.postInterceptors[i]));
			}
		}


实际上通知的执行顺序并不由将通知定义在preInterceptors或是postInterceptors中所决定,而是决定于通知实现与哪一个通知接口.

Spring 2.0貌似改进了这点,<tx:advice>标签可以不分前后,但TransactionProxyFactoryBean中看不到什么改变,仅仅是将一些方法继承自AbstractSingletonProxyFactoryBean?正在研究,有看法的话写出来大家一起讨论.
分享到:
评论
1 楼 roundlight 2007-07-24  
写的很好,我也在研究Spring ,更多关注
希望,有机会能多交流!

相关推荐

    spring事务与数据库操作

    ### Spring事务与数据库操作 #### 一、Spring的声明式事务管理 在现代软件开发中,事务处理是非常关键的一部分,特别是在涉及多个数据操作时。Spring框架提供了强大的事务管理能力,可以方便地集成到应用程序中。...

    SPRING事务机制DEMO

    Spring事务机制是Java开发中非常重要的一个概念,它在企业级应用中扮演着核心角色,确保数据的一致性和完整性。Spring提供了多种事务管理方式,包括编程式事务管理和声明式事务管理。在这篇DEMO中,我们将重点探讨...

    spring 事务(6中配置完全降解)

    本篇文章将详细解析Spring中的六种事务配置方法,帮助开发者深入理解并掌握Spring事务的运用。 1. **基于XML的事务配置** Spring支持通过XML配置来管理事务,这是最基础的配置方式。在`spring`的配置文件中,我们...

    spring事务管理

    ### Spring事务管理详解 #### 一、Spring事务管理概述 Spring框架提供了强大的事务管理功能,使得开发者能够更方便地管理应用程序中的事务。Spring事务管理主要包括两种类型:编程式事务管理和声明式事务管理。 -...

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

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

    Spring基于XML方式配置事务

    事务通知定义了哪些方法应该在事务内执行。使用`&lt;tx:method&gt;`标签,可以指定匹配的方法名、传播行为、读写性质、隔离级别和超时时间。例如: ``` *" read-only="false"/&gt; ``` 这将使所有以`save`开头的方法都...

    spring3.0两种事务管理配置

    接下来,我们需要定义事务通知,包括定义方法的过滤规则,所有方法都使用事务,并且定义所有 get 开头的方法都是只读的。 最后,我们需要定义 AOP 配置,包括定义一个切入点,定义事务的通知,进行适配。 基于 @...

    Spring aop、jdbc和事务tx练习

    本练习主要涵盖了Spring的三个方面:面向切面编程(AOP)、JDBC(Java Database Connectivity)以及事务管理(TX)。让我们详细探讨这些知识点。 1. **Spring AOP(面向切面编程)** 面向切面编程是Spring框架的一...

    Spring 前置通知和后置通知

    在Spring框架中,AOP(面向切面编程)是一种强大的设计模式,它允许开发者将关注点从业务逻辑中分离出来,比如日志记录、事务管理等。本文将深入探讨Spring AOP中的前置通知和后置通知,以及它们在实际开发中的应用...

    Spring通知的配置

    在深入探讨Spring通知的配置之前,我们先简要回顾一下Spring框架的核心概念。Spring是一个开源的、轻量级的Java应用框架,旨在简化企业级应用的开发。它提供了丰富的功能,包括依赖注入(Dependency Injection,DI)...

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

    在IT行业中,MyBatis、Spring AOP、Spring事务管理和反射工具类是常见的技术栈,它们在构建高效、灵活的企业级应用中起着至关重要的作用。以下是对这些知识点的详细阐述: 1. MyBatis拦截器(MyBatis Interceptor)...

    Spring_tx事务

    本篇文章将深入探讨Spring事务管理的基础知识、工作原理以及如何在实际项目中应用。 首先,事务是数据库操作的基本单位,它确保了一组操作要么全部成功,要么全部失败,从而保证了数据的完整性和一致性。在Spring中...

    Spring源代码解析(六):Spring声明式事务处理.doc

    Spring 声明式事务处理 Spring 中的事务处理可以分为两种方式:声明式事务处理和编程式事务处理。声明式事务处理通过 AOP 的实现,把事务管理代码作为方面封装到业务代码中,使得事务管理代码和业务代码解藕。这...

    spring通知例子

    本例"spring通知例子"着重展示了如何利用Spring AOP实现操作日志的拦截,这涉及到前置通知(Before Advice)和后置通知(After Advice)的概念。 首先,我们需要理解什么是Spring AOP。AOP的核心是切面(Aspect),...

    Spring声明式事务处理

    声明式事务处理的核心是基于AOP(面向切面编程)的,Spring通过在事务边界添加通知(advice)来实现事务管理。这包括开始事务、提交事务、回滚事务等操作。用户只需在配置文件或使用注解来声明哪些方法需要在事务中...

    spring,struts,hibernate,事务

    例如,可以在XML配置文件中定义一个事务通知,然后将其应用到具有特定注解或接口的类或方法上。这样,当新的DAO或Mgr需要事务支持时,只需要简单地加入对应的注解或实现指定的接口,而无需修改现有的事务配置。 在...

    spring基于AspectJ实现事务控制

    2. **定义事务切面**:创建一个包含事务处理逻辑的切面类,该类通常会包含一个或多个通知(advice),如`@Before`、`@After`、`@Around`等。在Spring中,我们主要使用`@Transactional`注解来声明一个方法需要进行...

    Spring延迟加载和声明式事务处理最终解决方案(修正版)

    - **XML配置**:在Spring的配置文件中定义事务管理器(如`PlatformTransactionManager`),并声明事务的通知(advice),指定哪些方法需要进行事务处理。 - **Java配置**:使用`@EnableTransactionManagement`注解...

    spring事务与配置

    通过`aop:advisor`将事务通知与切入点关联起来。 ##### 第三种方式:基于注解的声明式事务 这种方式使用注解来指定事务行为,是目前最常用的事务配置方式。它简洁明了,能够很好地减少配置文件的复杂度。 **配置...

    Spring配置JTA事务管理

    - 事务同步:Spring的`TransactionSynchronization`接口允许你在事务的开始、结束、提交或回滚时执行额外的任务,比如清理缓存或发送通知。 - JTA的并发问题:在多线程环境下,你需要理解如何避免死锁和其他并发问题...

Global site tag (gtag.js) - Google Analytics