【轉】Controller中為什么不能寫@Transactional


Controller中為什么不能寫@Transactional
原文鏈接:http://sunbingbing.cn/controller中為什么不能寫transactional/

1.背景

Controller指SpringMVC項目中用於定義接口信息的類,該類一般會被@Controller或@RestController等SpringMVC相關注解標記;
@Transactional指spring-tx包中定義的事務注解,被該注解標記的方法或類將成為一個整體,“同進同退”;
在開發過程中,注解是我們的神兵利器,但如果不恰當的使用將會造成嚴重的問題。

2.問題

  • 在Controller層的接口定義處添加@Transactional
  • 對Controller層進行統一代理,添加公共校驗等攔截
  • 添加過@Transactional的Controller接口失效,請求返回404

3.解決方案
方案一:調整@Transactional到service層
方案二:添加cglib依賴,指定強制使用cglib代理

4.問題分析

  • 從@Transactional入手分析;Spring在掃描bean 的時候,發現某些類或方法上添加了事務注解,就會生成該類的代理類,並賦予代理類事務的相關邏輯,從而達到事務效果;我們在實際調用中,調用的是對應的代理類而非其本身。

  • 從Controller層代理入手分析;通過相關工具類例如BeanNameAutoProxyCreater對controller進行統一代理,並插入統一的校驗邏輯,達到快速開發的目的;同樣的在實際調用中,我們調用到的也是其對應的代理類而非其本身。

*從代理方面入手分析;SpringAOP部分主要使用JDK動態代理或cglib代理;默認情況下,如果被代理的目標對象實現了至少一個接口,則會使用jdk動態代理,否則會通過cglib創建代理類,但也可以通過設置強制使用cglib進行代理操作。

*結合以上分析,404的Controller被代理了兩次,因controller沒有實現接口,所以第一次代理一定是cglib代理;因設置強制使用cglib代理可解決404問題反推,第二次代理一定是jdk動態代理;結合以上推測,第二次jdk動態代理時可能導致@RequestMapping等注解失效,最終造成404問題。

5.相關問題
本次問題的引發原因是對現有工程新增統一驗證邏輯導致,同步發現的問題還有Controller中的自動注入失敗,導致執行service中邏輯時報404;原因時Controller中方法為private,private的方法不會被代理,導致引用的service屬性沒有完成注入。

6.開發規范

  • Controller中不要添加@Transactional等注解,該類注解一律放到service中;
  • Controller中被定義為接口的方法不要定義為private

7.加buffer

public static void main(String[] args){
    //生成代理類的class文件到工程根目錄
    System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
  //生成cglib代理的class文件到指定目錄
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"e:\\cglib");
    SpringApplication.run(Application.class);
}


免責聲明!

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



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