@Transactional使自定義注解失效


問題背景:

要添加@Transactional注解,使某功能可以原子操作。

接口調用結構:controller->processor(類似Service層)->flow(類似Manager層)

附:推薦的工程結構:

1. 請求處理:(Web層)控制轉發

2. 業務邏輯(Service層)具體業務邏輯

3.通用處理 (Manager層)service能力下沉,緩存,三方平台,與DAO交互。

4.數據持久(DAO層)數據訪問,與MySQL交互。

調用過程:

controller到processor之間是通過統一的接口分發。

所有的processor都有自定義注解,里面存接口url路徑名。啟動時通過ApplicationContext.getBeansOfType()把所有processor注冊到一個map里。注冊時getAnnocation判斷自定義注解不為空,把其中的接口名作為key,真實的processor作為value。

controller收到請求,轉發給統一接口,統一的接口通過收到的url接口名,從map里找到對應的processor轉發。processor直接調對應的flow。

 

問題現象:

在processor的方法上加@Transactional注解。此時調不到對應的processor。

調試發現,在啟動注冊時,該processor里就沒有注冊進來,根據url在map里自然找不到對應的processor。沒注冊進來發生在clazz.getAnnocation時候得到的為空。

從IOC容器中獲取所有processor的bean的時候,獲取到了所有processor。但是在含有@Transaction注解的那個processor在獲得自定義注解內容的時候獲取不到。

所以是@Transaction使通過getAnnotation()獲取自定義注解失效。

 

產生原因:

@Transaction 的原理是AOP代理,從而使IOC中的bean是代理類,不是真實bean。自定義注解並沒有繼承過來,所以在代理類上找不到自定義注解。

 

解決方法:

1. 自定義注解在聲明的時候加上 @Inherited,表明該注解是可以被子類繼承的。父類有該注解子類也可以獲取該注解。對類的繼承有效,對接口的繼承和實現無效。所以注意使用該方法的前提是AOP的動態代理使用的cglib而不是JDK自帶的動態代理。

cglib是支撐基於類的動態代理,而JDK自帶的是基於接口的動態代理。 使用cglib配置  <aop:aspectj-autoproxy proxy-target-class="true"/>

2. 將@Transaction下沉到flow層。最簡單也最合理。

3. 可先通過AOP的代理類獲取原始類,再通過原始類去獲取注解。

先判斷是不是Advised的實例。所有AOP代理的類都可以轉型為Advised接口,可通過它找到原始類。 instanceof Advised。通過 getTargetSource()  getTarget() getClass() 獲取到原始類。https://blog.csdn.net/u011403655/article/details/52259566

 

由此可見雖然只在一個方法上加了@Transaction注解,但整個類都會被AOP代理。

 

為什么只有加@Transaction注解使自定義注解失效,而原先方法上的其他注解卻沒有影響到自定義注解?

@Transaction使用的是AOP的動態代理生成的代理類,其他注解不是AOP。

常見的AOP注解如:@Aspect,@Before,@After,@Around,@Transaction。

 

除了上面原因,還有什么情況,用getAnnotation獲取不到注解?

看注解的元注解@Retention定義的存活時間保留到什么時候,一般是Runtime,則可以在運行時通過getAnnotation獲取。其他如@Slf4j這個注解定義的存活時間是Source,為存活到編譯期。則獲取的就為null。

 


免責聲明!

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



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