最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

spring AOP注解失效原因分析及解決過程

 更新時間:2026年06月04日 10:55:57   作者:SeaDhdhdhdhdh  
Spring AOP注解失效原因及解決方法,詳細(xì)解析Spring動態(tài)代理機制,包括JDK動態(tài)代理和CGLIB動態(tài)代理,以及AOP注解在方法調(diào)用中的應(yīng)用問題和解決方案

@Transactional @Async等注解不起作用

之前很多人在使用Spring中的@Transactional, @Async等注解時,都多少碰到過注解不起作用的情況。

為什么會出現(xiàn)這些情況呢?因為這些注解的功能實際上都是Spring AOP實現(xiàn)的,而其實現(xiàn)原理是通過代理實現(xiàn)的。

JDK動態(tài)代理

以一個簡單的例子理解一下JDK動態(tài)代理的基本原理:

//目標(biāo)類接口
public interface JDKProxyTestService {
  void run();
}

//目標(biāo)類
public class JDKProxyTestServiceImpl implements JDKProxyTestService {
  public void run(){
    System.out.println("do something...");
  }
}

//代理類
public class TestJDKProxy implements InvocationHandler {

  private Object targetObject; //代理目標(biāo)對象

  //構(gòu)造代理對象
  public Object newProxy(Object targetObject) {
    this.targetObject = targetObject;
    return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
        targetObject.getClass().getInterfaces(), this);
  }

  //利用反射,在原邏輯上進(jìn)行邏輯增強
  public Object invoke(Object proxy, Method method, Object[] args)
      throws Throwable {
    //模擬事務(wù)開始
    assumeBeginTransaction();
    //原執(zhí)行邏輯
    Object ret = method.invoke(targetObject, args);
    //模擬事務(wù)提交
    assumeCommitTransaction();
    return ret;
  }

  private void assumeBeginTransaction() {
    System.out.println("模擬事務(wù)開始...");
  }

  private void assumeCommitTransaction() {
    System.out.println("模擬事務(wù)提交...");
  }
}

//測試
public class Test { 
  public static void main(String[] args) {
    TestJDKProxy jdkProxy = new TestJDKProxy();
    JDKProxyTestService proxy = (JDKProxyTestService) jdkProxy.newProxy(new JDKProxyTestServiceImpl());
    proxy.run();
  }
}

上面的例子應(yīng)該能夠清楚的解釋JDK動態(tài)代理的原理了。它利用反射機制,生成了一個實現(xiàn)代理接口的匿名類,在調(diào)用具體方法前調(diào)用InvokeHandler來處理。我們通過代理類對象調(diào)用方法時,實際上會先調(diào)用其invoke方法,里面再調(diào)用原方法。這樣我們可以在原方法邏輯的前后統(tǒng)一添加處理邏輯。

Spring還有一種動態(tài)代理方式是CGLIB動態(tài)代理。它是把代理對象類的class文件加載進(jìn)來,通過修改其字節(jié)碼生成子類來處理。雖然處理方式不一樣,但是代理的思想都是一致的。

如果被代理的目標(biāo)對象實現(xiàn)了接口,那么Spring會默認(rèn)使用JDK動態(tài)代理。所有該目標(biāo)類型實現(xiàn)的接口都將被代理。若該目標(biāo)對象沒有實現(xiàn)任何接口,則創(chuàng)建一個CGLIB代理。

Spring AOP注解失效原因及解決

基于以上對于動態(tài)代理原理的分析,我們來看以下兩個常見的問題:

原因1:同一個類中,方法A調(diào)用方法B(方法B上加有注解),注解無效

針對所有的Spring AOP注解,Spring在掃描bean的時候如果發(fā)現(xiàn)有此類注解,那么會動態(tài)構(gòu)造一個代理對象。

如果你想要通過類X的對象直接調(diào)用其中帶注解的A方法,此注解是有效的。因為此時,Spring會判斷你將要調(diào)用的方法上存在AOP注解,那么會使用類X的代理對象調(diào)用A方法。

但是假設(shè)類X中的A方法會調(diào)用帶注解的B方法,而你依然想要通過類X對象調(diào)用A方法,那么B方法上的注解是無效的。因為此時Spring判斷你調(diào)用的A并無注解,所以使用的還是原對象而非代理對象。接下來A再調(diào)用B時,在原對象內(nèi)B方法的注解當(dāng)然無效了。

解決方法:

最簡單的方式當(dāng)然是可以讓方法A和B沒有依賴,能夠直接通過類X的對象調(diào)用B方法。

但是很多時候可能我們的邏輯拆成這樣寫并不好,那么就還有一種方法:想辦法手動拿到代理對象。

AopContext類有一個currentProxy()方法,能夠直接拿到當(dāng)前類的代理對象。那么以上的例子,就可以這樣解決:

// 在A方法內(nèi)部調(diào)用B方法
// 1.直接調(diào)用B,注解失效。
B()
// 2.拿到代理類對象,再調(diào)用B。
((X)AopContext.currentProxy()).B()

原因2:AOP注解方法里使用@Autowired對象為null

在之前的使用中,出現(xiàn)過在加上注解的方法中,使用其他注入的對象時,發(fā)現(xiàn)對象并沒有被注入進(jìn)來,為null。

最終發(fā)現(xiàn),導(dǎo)致這種情況的原因是因為方法為private。因為Spring不管使用的是JDK動態(tài)代理還是CGLIB動態(tài)代理,一個是針對實現(xiàn)接口的類,一個是通過子類實現(xiàn)。無論是接口還是父類,顯然都不能出現(xiàn)private方法,否則子類或?qū)崿F(xiàn)類都不能覆蓋到。

如果方法為private,那么在代理過程中,根本找不到這個方法,引起代理對象創(chuàng)建出現(xiàn)問題,也導(dǎo)致了有的對象沒有注入進(jìn)去。

所以如果方法需要使用AOP注解,請把它設(shè)置為非private方法。

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 深入理解Java中的Lambda表達(dá)式

    深入理解Java中的Lambda表達(dá)式

    這篇文章主要介紹了深入理解Java中的Lambda表達(dá)式,Lambda在各編程語言中都是非常重要的特性,而Java中則加入得有些太晚...需要的朋友可以參考下
    2015-07-07
  • Spring實戰(zhàn)之使用@Resource配置依賴操作示例

    Spring實戰(zhàn)之使用@Resource配置依賴操作示例

    這篇文章主要介紹了Spring實戰(zhàn)之使用@Resource配置依賴操作,結(jié)合實例形式分析了Spring使用@Resource配置依賴具體步驟、實現(xiàn)及測試案例,需要的朋友可以參考下
    2019-12-12
  • Java實現(xiàn)員工管理系統(tǒng)

    Java實現(xiàn)員工管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了Java實現(xiàn)員工管理系統(tǒng),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • Java 字符串操作之contains 和 substring 方法最佳實踐與常見問題

    Java 字符串操作之contains 和 substring 方法最佳實踐與常

    本文給大家詳細(xì)介紹Java 字符串操作之contains 和 substring 方法最佳實踐與常見問題,本文結(jié)合實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2025-09-09
  • springboot?vue測試前端項目管理列表分頁功能實現(xiàn)

    springboot?vue測試前端項目管理列表分頁功能實現(xiàn)

    這篇文章主要為大家介紹了springboot?vue測試前端項目列表分頁功能實現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • mybatis中一對一、一對多的<association> 配置使用

    mybatis中一對一、一對多的<association> 配置使用

    <association>?是 MyBatis 中處理一對一或一對多關(guān)系的映射元素,用于處理一對一和一對多關(guān)系的映射,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-05-05
  • Spring?WebFlux?與?WebClient?使用指南及最佳實踐

    Spring?WebFlux?與?WebClient?使用指南及最佳實踐

    WebClient是Spring WebFlux模塊提供的非阻塞、響應(yīng)式HTTP客戶端,基于Project Reactor實現(xiàn),適用于高并發(fā)場景spring?webclient,本文給大家介紹Spring?WebFlux與WebClient使用指南及最佳實踐,感興趣的朋友一起看看吧
    2025-07-07
  • 一文剖析五種主流的Java字符串搜索匹配方案

    一文剖析五種主流的Java字符串搜索匹配方案

    這篇文章將深入剖析五種主流的Java字符串搜索匹配方案,通過原理分析、性能對比和場景建議,幫助你做出最優(yōu)的技術(shù)選型,感興趣的小伙伴可以了解下
    2026-02-02
  • 猜數(shù)游戲java實現(xiàn)代碼

    猜數(shù)游戲java實現(xiàn)代碼

    這篇文章主要為大家詳細(xì)介紹了java實現(xiàn)猜數(shù)游戲代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-12-12
  • IntelliJ?IDEA?代碼運行時中文出現(xiàn)亂碼問題及解決方法

    IntelliJ?IDEA?代碼運行時中文出現(xiàn)亂碼問題及解決方法

    在我們剛接觸到IDEA時,想美滋滋的敲一個“hello?world”來問候這個世界,但難免會遇到這種問題亂碼,這篇文章主要介紹了解決IntelliJ?IDEA?代碼運行時中文出現(xiàn)亂碼問題,需要的朋友可以參考下
    2023-09-09

最新評論

海淀区| 嵩明县| 晋宁县| 霍州市| 凉城县| 万山特区| 聊城市| 昔阳县| 岳西县| 兴文县| 梁河县| 木里| 桐乡市| 玉林市| 浮山县| 温泉县| 曲水县| 克拉玛依市| 蓬莱市| 九江市| 临武县| 陆川县| 金湖县| 化隆| 巴彦县| 巴林右旗| 宁陕县| 新宁县| 牡丹江市| 长岭县| 岢岚县| 莲花县| 砚山县| 桃源县| 青河县| 沁阳市| 奇台县| 花莲县| 九江县| 靖西县| 泾源县|