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

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

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

 

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

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

簡單來講,若是實現了某個接口,那麼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 調用方法

相關文章
相關標籤/搜索