SpringBoot CGLIB AOP解決Spring事務,對象調用自己方法事務失效.


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

當然可以使用原生ASPECTJ,不用SpringAOP,但是基於生態鏈問題,還是盡量使用SpringAOP

 

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

Spring 代理對象,cglib,jdk的問題思考,AOP 配置注解攔截 的一些問題.為什么不要注解在接口,以及抽象方法.

簡單來說,如果實現了某個接口,那么Spring就選擇JDK代理(不一定),如果沒有,那么就選擇CGLIB代理,說起來簡單,Spring還會鬧脾氣,不代理呢

 

 

點擊:根據Spring代理對象獲得真實對象

 

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

考慮以下問題: 同對象的方法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 的情況下(根據接口代理))

 @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()) 會拋出異常

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM