class Service {
public void A() {
// 調(diào)用本類其他方法,事務(wù)失效
this.B();
}
@Transactional
public void B() {
}
}
如上代碼,在同一個(gè)類中砰奕,非事務(wù)方法A調(diào)用事務(wù)方法B,會(huì)導(dǎo)致事務(wù)失效提鸟,可以采用AopContext.currentProxy().xxxxx()來保證事務(wù)生效军援。
無法切入的原因:
切入原理:創(chuàng)建代理類,在代理類中調(diào)用目標(biāo)方法時(shí)進(jìn)行切入称勋。
上面代碼胸哥,此時(shí)目標(biāo)對(duì)象service,代理對(duì)象是Proxy_0赡鲜,在同類Service中A方法調(diào)用B空厌,本質(zhì)是 this.B(),而不是Proxy_0.B()
其他解決辦法
ApplicationContext.getBean()
在本類中注入自己
使用手動(dòng)事務(wù)
注意事項(xiàng):
Spring Boot需要在啟動(dòng)類加上以下注解
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
SSM需要xml文件配置
<aop:aspectj-autoproxy proxy-target-class="true"expose-proxy="true"/>
為什么AopContext可以解決同類方法AOP失效問題
AopContext類的源碼如下
package org.springframework.aop.framework;
import org.springframework.core.NamedThreadLocal;
import org.springframework.lang.Nullable;
public final class AopContext {
// 維護(hù)了一個(gè)ThreadLocal银酬,存放AOP代理類
private static final ThreadLocal<Object> currentProxy = new NamedThreadLocal<>("Current AOP proxy");
private AopContext() {
}
public static Object currentProxy() throws IllegalStateException {
Object proxy = currentProxy.get();
if (proxy == null) {
throw new IllegalStateException(
"Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available, and " +
"ensure that AopContext.currentProxy() is invoked in the same thread as the AOP invocation context.");
}
return proxy;
}
// 提供代理類set進(jìn)ThreadLocal方法
@Nullable
static Object setCurrentProxy(@Nullable Object proxy) {
Object old = currentProxy.get();
if (proxy != null) {
currentProxy.set(proxy);
}
else {
currentProxy.remove();
}
return old;
}
}
Spring中創(chuàng)建動(dòng)態(tài)代理有兩種方式
JDK動(dòng)態(tài)代理
cglib動(dòng)態(tài)代理
jdk動(dòng)態(tài)代理創(chuàng)建時(shí)JdkDynamicAopProxy中的invoke方法中調(diào)用AopContext存入代理類
cglib動(dòng)態(tài)代理CglibAopProxy在創(chuàng)建代理時(shí)也調(diào)用AopContext存入代理類