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?正在研究,有看法的话写出来大家一起讨论.
分享到:
相关推荐
spring事务管理几种方式代码实例:涉及编程式事务,声明式事务之拦截器代理方式、AOP切面通知方式、AspectJ注解方式,通过不同方式实例代码展现,总结spring事务管理的一般规律,从宏观上加深理解spring事务管理特性...
基于springcloud+springboot+nacos+openFeign的分布式事务组件seata项目源码.zip 介绍 分布式事务组件seata的使用demo,AT模式、TCC模式,集成springboot、springcloud(nacos注册中心、openFeign服务调用、Ribbon...
TX_LCN5.0.2同一个微服务模块多实例,TM会发生事务通知TC错乱的问题,尤其是负载多实例,LCN分布式事务多模块错乱
5.1.8.3Spring事务的隔离级别 117 拓展: 118 5.1.8.4以XML配置的 形式 119 拓展: 120 5.1.8.5以注解方式配置 125 拓展: 127 5.1.9使用CGLIB以XML形式配置事务 130 5.2 Spring+Hibernate 131 5.2.1 ...
9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. <tx:advice/> 有关的设置 9.5.6. 使用 @Transactional 9.5.6.1. @Transactional 有关的设置 ...
14.5.1.理解Spring.NET声明式事务管理的实现 14.5.2.第一个例子 14.5.3.Transaction特性的设置 14.5.4.通过AutoProxyCreator使用声明式事务 14.5.5.通过TransactionProxyFactoryObject使用声明式事务 14.5.6. 通过...
LCN5.0.2同一个微服务模块多实例,TM会发生事务通知TC错乱的问题,解决分布式事务问题,尤其是多实例负载集群问题
JdbcDaoSupport、使用 NamedParameterJdbcTemplate、Spring 的声明式事务、事务的属性(传播行为、隔离级别、回滚属性、只读属性、过期时间)、使用 XML 文件的方式配置事务、整合 Hibernate、整合 Struts2 等。
9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. <tx:advice/> 有关的设置 9.5.6. 使用 @Transactional 9.5.7. 插入事务操作 9.5.8. ...
用spring AOP(包括几种常用的通知类型)做的小程序
9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. <tx:advice/> 有关的设置 9.5.6. 使用 @Transactional 9.5.7. 事务传播 9.5.8. 通知...
9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. <tx:advice/> 有关的设置 9.5.6. 使用 @Transactional 9.5.7. 插入事务操作 9.5.8. ...
Spring IOC 控制反转:把创建对象的权利交给Spring 创建对象 1.无参构造 2.静态工厂 3.实例工厂 管理对象 对象关系DI 构造器注入 set注入 生命周期 scope:prototype/singleton init-...
9.5.1. 理解Spring的声明式事务管理实现 9.5.2. 第一个例子 9.5.3. 回滚 9.5.4. 为不同的bean配置不同的事务语义 9.5.5. <tx:advice/> 有关的设置 9.5.6. 使用 @Transactional 9.5.7. 事务传播 9.5.8. 通知...
49. Spring 框架的事务管理有哪些优点? 50. 你更倾向用那种事务管理类型? 51. 解释 AOP 52. Aspect 切面 53. 在 Spring AOP 中,关注点和横切关注的区别是什么? 54. 连接点 55. 通知 56. 切点 57. 什么是引入? ...
5.1.2 理解Spring对事务管理的支持 5.1.3 介绍Spring的事务管理器 5.2 在Spring中编写事务 5.3 声明式事务 5.3.1 理解事务属性 5.3.2 声明一个简单的事务策略 5.4 通过方法名声明事务 ...
Spring+iBatis+JOTM实现JTA事务: 如何处理跨库事物:spring + jtom 的jta事务是个很好的选择. 这个源码示例非常不错,包括所有的源码和jar包,下载后eclipse 或 myeclipse 导入就能用。 里面有详细的说明和注释,...
13.6 管理集成测试中的事务 530 13.6.1 问题 530 13.6.2 解决方案 530 13.6.3 工作原理 531 13.7 在集成测试中访问数据库 536 13.7.1 问题 536 13.7.2 解决方案 536 13.7.3 工作原理 537 13.8 使用...
13.6 管理集成测试中的事务 530 13.6.1 问题 530 13.6.2 解决方案 530 13.6.3 工作原理 531 13.7 在集成测试中访问数据库 536 13.7.1 问题 536 13.7.2 解决方案 536 13.7.3 工作原理 537 13.8 使用...