浏览 4416 次
锁定老帖子 主题:Spring的事务通知
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2007-07-11
看到这里有一些疑惑,在事务声明中,如果一个事务代理设置给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?正在研究,有看法的话写出来大家一起讨论. 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |