起因:
做的项目,三层架构:domain层(dao)、façade层(business)、view层。View层用Extjs实现,使用SSH组合,在façade层配置了REQUIRED型事务,在domain层没有采用默认事务。按说,在façade层配置了事务之后,同一次操作(同一个façade方法)对domain层的调用一定应该是同一事务,这个由spring保证的。但领导怀疑看到有不一致的数据,怀疑是由于同一次操作没有在同一事务中(应该是系统开发过程中不完善造成的),让验证一下同一次façade层的操作,对domain层是不是在同一个事务中。
验证方法有两种:
1. 在一次façade层的方法入口处获取事务,保存,然后在调用相关的domain层方法中手动添加获取事务,验证和入口处的事务是不是同一事务。这种方案需要先在各相关方法中添加代码,验证完成后,再把新加的代码清除,工作量大,而且易出错。
2. 通过spring的aop功能,生成切面,在每个facade方法调用的domain方法前或后得到事务,验证同一次操作对domain层的方法是否在同一事务中。
鉴于第二种方法只需要独立生成一个新切面类,并修改配置方法就可以完成,而且可以借此机会学习一下spring的aop,所以决定采用第二种方案。
首先实现一个切面类:
public class MyAspect {
public void doAfter(JoinPoint jp){
System.out.println("log Ending method: "
+ jp.getTarget().getClass().getName() + "."
+ jp.getSignature().getName());
}
public void doBefore(JoinPoint jp) {
System.out.println("log Begining method: "
+ jp.getTarget().getClass().getName() + "."
+ jp.getSignature().getName()); }
}
然后修改spring配置文件beans.xml,添加如下内容:
<!--切面实现1 Begin -->
<aop:config>
<aop:pointcut id="myAspectAA" expression="execution(* com.dfsoft.hummer.domain..*Impl.add*(..)) or execution(* com.dfsoft.hummer.domain..*Impl.del*(..)) or execution(* com.dfsoft.hummer.domain..*Impl.save*(..))"/>
<aop:aspect id="myAspect" ref="myAspect1">
<aop:before pointcut-ref="myAspectAA" method="doBefore"/>
<aop:after pointcut-ref="myAspectAA" method="doAfter"/>
</aop:aspect>
</aop:config>
<bean id="myAspect1" class="com.dfsoft.hummer.domain.common.MyAspect" />
<!-- 切面实现1 End-->
运行程序,进行相关操作,查看结果,看到切面成功执行。
验证同一façade方法对domain的调用是否在同一事务,只需要使用before或after一个就行,我这里使用了before。修改before方法如下:
public void doBefore(JoinPoint jp) {
System.out.println();
try{
Method m = jp.getTarget().getClass().getDeclaredMethod("getSession"); //反射
m.setAccessible(true); //使私有方法可操作
Session s = (Session)m.invoke(jp.getTarget());
System.out.println(s.getTransaction().hashCode());
}catch(Exception e){
System.out.println("No such method: " + e.getMessage());
}
System.out.println("log Begining method: "
+ jp.getTarget().getClass().getName() + "."
+ jp.getSignature().getName());
}
再一次运行程序,进行相关操作,查看控制台,看到同一次操作输入的事务的hashcode是同一个,这就可以认为同一次façade方法调用,所有的domain调用是在同一事务中。
验证完成后,删除MyAspect类,清除配置文件中修改,就完成了还原的工作。
本来一个功能是应该写测试来保证后续的修改不会引入错误,但考虑到这个工作是一次性的,用完就清除了,所以就没有写测试。