Spring AOP之同一個對象方法內部自調用致使事務失效問題

對於像我這種喜歡濫用AOP的程序員,遇到坑也是習慣了,不單單是事務,其實只要脫離了Spring容器管理的全部對象,對於SpringAOP的註解都會失效,由於他們不是Spring容器的代理類,SpringAOP,就切入不了程序員

固然可使用原生ASPECTJ,不用SpringAOP,可是基於生態鏈問題,仍是儘可能使用SpringAOPide

這裏簡單說一下,Spring如何選擇使用CGLIB,或者是JDK代理,this

簡單來講,若是實現了某個接口,那麼Spring就選擇JDK代理(不必定),若是沒有,那麼就選擇CGLIB代理,提及來簡單,Spring還會鬧脾氣,不代理呢spa

 

問題引出

一直以來比較多的狀況是在Controller 調用Service 的方法,把事務直接在Service的方法上,妥妥的沒問題,事務正常執行.net

考慮如下問題: 同對象的方法B 調用本身的方法A,這裏的事務將會失效(嚴格上來講,只要對方法A使用註解AOP均會失效),緣由是由於這裏的this.調用的並非Spring的代理對象代理

@Service
public class ClassA{

        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void methodA(){

        }

        /**
         * 這裏調用methodA() 的事務將會失效
         */
        public void methodB(){
            this.methodA();
        }

    }

解決方法一

最簡單的解決方法爲:(代理模式爲JDK 的狀況下(根據接口代理))code

 @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();
        }

    }

解決方法二

解決第一步: 必須對象

SpringBoot:註解開啓cglib代理,開啓 exposeProxy = true,暴露代理對象 (不然AopContext.currentProxy()) 會拋出異常blog

@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 調用方法

 

 

 

https://blog.csdn.net/benben683280/article/details/78839853

相關文章
相關標籤/搜索