前两天面试的时候,面试官问了一个问题,大概意思就是一个类有两个成员方法 A 和 B,两者都加了事务处理注解,定义了事务传播级别为 REQUIRE_NEW,问 A 方法内部直接调用 B 方法时能否触发事务处理机制。
答案有点复杂,Spring 的事务处理其实是通过AOP实现的,而实现AOP的方法有好几种,对于通过 Jdk 和 cglib 实现的 aop 处理,上述问题的答案为否,对于通过AspectJ实现的,上述问题答案为是。
本文就结合具体例子来看一下,我们先定义一个接口
public interface AopActionInf {
void doSomething_01();
void doSomething_02();
}
以及此接口的一个实现类,
public class AopActionImpl implements AopActionInf{
public void doSomething_01() {
System.out.println("AopActionImpl.doSomething_01()");
//内部调用方法 doSomething_02
this.doSomething_02();
}
public void doSomething_02() {
System.out.println("AopActionImpl.doSomething_02()");
}
}
增加AOP处理
public class ActionAspectXML {
public Object aroundMethod(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("进入环绕通知");
Object object = pjp.proceed();//执行该方法
System.out.println("退出方法");
return object;
}
}
<aop:aspectj-autoproxy/>
<bean id="actionImpl" class="com.maowei.learning.aop.AopActionImpl"/>
<bean id="actionAspectXML" class="com.maowei.learning.aop.ActionAspectXML"/>
<aop:config>
<aop:aspect id = "aspectXML" ref="actionAspectXML">
<aop:pointcut id="anyMethod" expression="execution(* com.maowei.learning.aop.AopActionImpl.*(..))"/>
<aop:around method="aroundMethod" pointcut-ref="anyMethod"/>
</aop:aspect>
</aop:config>
运行结果如下:
下图是断点分析在调用方法doSomething_02时的线程栈,很明显在调用doSomething_02时并没有对其进行AOP处理。
默认情况下,Spring AOP使用Jdk的动态代理机制实现,当然也可以通过如下配置更改为cglib实现,但是运行结果相同,此处不再赘述。
<aop:aspectj-autoproxy proxy-target-class="true"/>
那有没有办法能够触发AOP处理呢?答案是有的,考虑到AOP是通过动态生成目标对象的代理对象而实现的,那么只要在调用方法时改为调用代理对象的目标方法即可。
我们将调用 doSomething_02 的那行代码改成如下,并修改相应配置信息:
public void doSomething_01() {
System.out.println("AopActionImpl.doSomething_01()");
((AopActionInf) AopContext.currentProxy()).doSomething_02();
}
<aop:aspectj-autoproxy expose-proxy="true"/>
先来看一下运行结果,
从运行结果可以看出,嵌套调用方法已经能够实现AOP处理了,同样我们看一下线程调用栈信息,显然 doSomething_02 方法被增强处理了(红框中内容)。