天天看點

@transactional注解_為啥同一個類中普通方法調用Spring注解方法,注解會失效?看完你就明白,So easy!...

@transactional注解_為啥同一個類中普通方法調用Spring注解方法,注解會失效?看完你就明白,So easy!...

Spring注解(如@Transactional、@Cacheable、@Async等),在使用不當時,很可能會失效。失效的情況有很多種,本文我們就來瞅瞅,為啥同一個類中普通方法調用Spring注解方法,注解會失效呢?

有一些同學可能不知道其中原由,别急,讓我來為大家揭曉答案。

@transactional注解_為啥同一個類中普通方法調用Spring注解方法,注解會失效?看完你就明白,So easy!...

聽說你很懂源碼?Spring讀懂了?還有這20道源碼面試題接得住嗎?​zhuanlan.zhihu.com

@transactional注解_為啥同一個類中普通方法調用Spring注解方法,注解會失效?看完你就明白,So easy!...

Spring在掃描bean的時候,如果掃描到方法上有這些注解,那麼spring會通過動态代理模式,為這個bean動态地生成一個代理類,在代理類中,會對有注解的這個方法,做一些增強處理,如給有@Transactional注解的方法開啟transaction。

當我們想要調用這個方法時,實際上是先調用了代理對象中被增強的方法,然後在代理對象中,又會調用我們實際的目标對象中的方法。在通過代理對象中轉的這一過程中,像上邊說的開啟和送出transaction就實作了。

實作機制我們大體知道了,下面我們用代碼來模拟示範一下。

假設我們訂單業務處理類中,有兩個方法:校驗訂單參數方法verifyOrderParameters() 和 儲存訂單方法saveOrder(),其中saveOrder方法上加了@Transactional注解,verifyOrderParameters方法内會調用saveOrder方法。

OrderService

/**
 * 訂單業務層的接口定義
 */
public interface OrderService {

    /**
     * 校驗訂單參數
     */
    void verifyOrderParameters();

    /**
     * 儲存訂單
     */
    void saveOrder();
}
           

OrderServiceImpl

/**
 * 訂單業務層的具體處理類
 */
public class OrderServiceImpl implements OrderService{

    @Override
    public void verifyOrderParameters() {
        System.out.println("校驗訂單參數");
        // 調用儲存訂單方法
        saveOrder();
    }

    @Override
    @Transactional
    public void saveOrder() {
        System.out.println("儲存訂單資訊到DB");
    }
}
           

我們用僞代碼來示範一下Spring動态代理生成的代理類。

OrderServiceImplProxy

/**
 * 訂單業務層具體處理類的代理類
 */
public class OrderServiceImplProxy implements OrderService{

    /**
     * 持有被代理的具體的目标對象
     */
    private OrderServiceImpl orderServiceImpl;

    public OrderServiceImplProxy(OrderServiceImpl orderServiceImpl) {
        this.orderServiceImpl = orderServiceImpl;
    }

    @Override
    public void verifyOrderParameters() {
        orderServiceImpl.verifyOrderParameters();
    }

    @Override
    public void saveOrder() {
        System.out.println("開啟事務。。。");
        orderServiceImpl.saveOrder();
        System.out.println("送出事務。。。");
    }
}
           

邊我們來看下用戶端調用saveOrder方法和verifyOrderParameters方法,輸出結果都是什麼樣的。

public class Client {

    public static void main(String[] args) {
        // 建立一個訂單業務的真實處理對象
        OrderServiceImpl orderServiceImpl = new OrderServiceImpl();
        // 建立一個代理對象
        OrderServiceImplProxy orderServiceImplProxy = new OrderServiceImplProxy(orderServiceImpl);
        // 執行代理對象的校驗訂單方法
        orderServiceImplProxy.verifyOrderParameters();
        System.out.println("--------------------------------------------");
        // 執行代理對象的儲存訂單方法
        orderServiceImplProxy.saveOrder();
    }
}
           

執行main方法後,得到下邊的輸出:

校驗訂單參數

儲存訂單資訊到DB

--------------------------------------------

開啟事務。。。

儲存訂單資訊到DB

送出事務。。。

通過這個示範代碼,想必同學們已經了解了吧,普通方法verifyOrderParameters内調用注解方法saveOrder時,其實調用的是原目标對象(orderServiceImpl)的saveOrder方法,沒有走代理對象(orderServiceImplProxy)中被增強的saveOrder方法,是以就不會産生效果啦。

動态代理是實作Spring AOP的一個重要手段,是以大家以後再用注解以及切面時,一定要注意這個坑噢。

作者:曉呆同學

原文連結: https:// blog.csdn.net/daidainet easy/article/details/105981724