1. 程式人生 > >Spring aop註解失效

Spring aop註解失效

led end int pos 調用 cnblogs 問題 lock 查看

問題

在spring 中使用 @Transactional 、 @Cacheable 或 自定義 AOP 註解時,對象內部方法中調用該對象的其他使用aop機制的方法會失效。

     @Transactional
    public void saveFile(FileDetail sourceFile, FileDetail targetFile, FileRelation fileRelation) {
    
            sourceFile = fileDao.queryFileByMd5(sourceFile.getMd5());
            fileDao.insertFile(sourceFile);
            fileRelationDao.insertFileRelation(fileRelation);
            sendMessage();
    }
    
    public void sendMessage(){
        System.out.println("打日誌");
        System.out.println("發送消息...");
    }
    

在同一個類中的方法級別調用也會導致 aop 註解失效

原因

Spring AOP使用JDK動態代理和CGLib,由於沒有接口的類,所以使用CGLib代理。當方法被代理時,其實通過動態代理生成了代理對象,然後代理對象執行invoke方法,在調用被代理對象的方法時,執行其他操作。問題就在於被代理對象的方法中調用被代理對象的其他方法時,使用的是被代理對象本身,而非代理對象。這就導致了一個方法時代理對象調用的,一個是被代理對象調用的。他們的調用始終不出於同一個對象。

實例

(1)當我們調用saveFile(),spring的動態代理會動態生成一個代理對象(serviceFile)。
(2)當我們調用saveFile的時候實際上是serviceFile調用。
(3)當調用saveFile()方法內調用同一個類的另外一個註解方法sendMessage時,實際上是使用this.saveFile(),而this指當前對象而非代理對象,所以註解失效。

解決方案

通過AopContext.currentProxy()獲取當前代理對象。

1.AopContext.currentProxy();

2.修改 xml

     @Transactional
    public void saveFile(FileDetail sourceFile, FileDetail targetFile, FileRelation fileRelation) {
    
            sourceFile = fileDao.queryFileByMd5(sourceFile.getMd5());
            fileDao.insertFile(sourceFile);
            fileRelationDao.insertFileRelation(fileRelation);
            (FileService)AopContext.currentProxy().sendMessage();
    }
    
    @Transactional
    public void sendMessage(){
        System.out.println("打日誌");
        System.out.println("發送消息...");
    }
    

配置

   <tx:annotation-driven transaction-manager="transactionManager"/>
<!-- (事務管理)transaction manager, use JtaTransactionManager for global tx -->
<bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      <property name="dataSource" ref="dataSourceForSqlServer" />
</bean>

註意事項

1.在需要事務管理的地方加@Transactional 註解。@Transactional 註解可以被應用於接口定義和接口方法、類定義和類的 public 方法上 。
2.@Transactional 註解只能應用到 public 可見度的方法上 。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 註解,它也不會報錯, 但是這個被註解的方法將不會展示已配置的事務設置。
3.註意僅僅 @Transactional 註解的出現不足於開啟事務行為,它僅僅 是一種元數據。必須在配置文件中使用配置元素,才真正開啟了事務.
4.spring事物是基於類和接口的所以只能在類裏面調用另一個類裏面的事物,同一個類裏面調用自己類的事物方法是無效的。spring事物也不要頻繁使用,在事物處理的同時操作的第一張表會被限制查看的(即被臨時鎖住)。數據量大的時候會有一定影響。

參考

[1][spring aop註解失效之謎](http://blog.csdn.net/u012373815/article/details/77345655)
[2]Spring @Transactional事物配置無效原因
[3]Does Spring @Transactional attribute work on a private method?

Spring aop註解失效