
Spring注解(如@Transactional、@Cacheable、@Async等),在使用不當時,很可能會失效。失效的情況有很多種,本文我們就來瞅瞅,為啥同一個類中普通方法調用Spring注解方法,注解會失效呢?
有一些同學可能不知道其中原由,别急,讓我來為大家揭曉答案。
聽說你很懂源碼?Spring讀懂了?還有這20道源碼面試題接得住嗎?zhuanlan.zhihu.com
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