對於像我這種喜歡濫用AOP的程序員,遇到坑也是習慣了,不單單是事務,其實只要脫離了Spring容器管理的全部對象,對於SpringAOP的註解都會失效,由於他們不是Spring容器的代理類,SpringAOP,就切入不了html
固然可使用原生ASPECTJ,不用SpringAOP,可是基於生態鏈問題,仍是儘可能使用SpringAOP程序員
這裏簡單說一下,Spring如何選擇使用CGLIB,或者是JDK代理,dom
簡單來講,若是實現了某個接口,那麼Spring就選擇JDK代理(不必定),若是沒有,那麼就選擇CGLIB代理,提及來簡單,Spring還會鬧脾氣,不代理呢ide
點擊:根據Spring代理對象得到真實對象post
一直以來比較多的狀況是在Controller 調用Service 的方法,把事務直接在Service的方法上,妥妥的沒問題,事務正常執行this
考慮如下問題: 同對象的方法B 調用本身的方法A,這裏的事務將會失效(嚴格上來講,只要對方法A使用註解AOP均會失效),緣由是由於這裏的this.調用的並非Spring的代理對象url
@Service
public class ClassA{ @Transactional(propagation = Propagation.REQUIRES_NEW) public void methodA(){ } /** * 這裏調用methodA() 的事務將會失效 */ public void methodB(){ this.methodA(); } }
最簡單的解決方法爲:(代理模式爲JDK 的狀況下(根據接口代理))spa
@Service public class ClassA extends BaseClass{ @Transactional(propagation = Propagation.REQUIRES_NEW)
@Override public void methodA(){ } /** * 這裏調用methodA() 的事務將會失效 */
public void methodB(){ //使用getBean ((BaseClass)SpringUtil.getBean("classA")).methodA(); } }
第二種方式:代理
解決第一步: 必須code
SpringBoot:註解開啓cglib代理,開啓 exposeProxy = true,暴露代理對象 (不然AopContext.currentProxy()) 會拋出異常
@EnableAspectJAutoProxy(exposeProxy = true) public class Application{ public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
配置方式:配置方式下,我用的是SpringBoot 1.5.4沒有找到exposeProxy的選項,因此建議使用註解式.
傳統Spring配置文件
XML
<aop:aspectj-autoproxy expose-proxy="true"/>
第二步(須要保證Spring對這個bean建立了代理對象,基本上涉及到Aop的方法的類,都會建立代理對象) 能夠用如下代碼判斷
/** * Created by laizhenwei on 19:37 2017-10-14 */ @Service("classImplProxy") @Scope(proxyMode = ScopedProxyMode.INTERFACES) public class ClassImplProxy implements IClass { @Override @Transactional public void sysout() { } //是否代理對象 @Override public boolean isAopProxy() { return AopUtils.isAopProxy(AopContext.currentProxy()); } //是否cglib 代理對象 @Override public boolean isCglibProxy() { return AopUtils.isCglibProxy(AopContext.currentProxy()); } //是否jdk動態代理 @Override public boolean isJdkDynamicProxy() { return AopUtils.isJdkDynamicProxy(AopContext.currentProxy()); } }
獲取代理對象
@Service public class ClassA{ @Transactional(propagation = Propagation.REQUIRES_NEW) public void methodA(){ } public void methodB(){ //手動獲取此對象Spring的代理類 ((ClassA)AopContext.currentProxy()).methodA();
} }
第三種方式
直接在當前類@Autowire 或者@Resource 注入本身,而後用注入的bean 調用方法