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

Spring AOP注解失效的坑及JDK動(dòng)態(tài)代理

 更新時(shí)間:2018年03月27日 16:23:11   作者:白色夜空  
這篇文章主要介紹了Spring AOP注解失效的坑及JDK動(dòng)態(tài)代理,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧

@Transactional @Async等注解不起作用

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

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

JDK動(dòng)態(tài)代理

以一個(gè)簡單的例子理解一下JDK動(dòng)態(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)行邏輯增強(qiáng)
  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動(dòng)態(tài)代理的原理了。它利用反射機(jī)制,生成了一個(gè)實(shí)現(xiàn)代理接口的匿名類,在調(diào)用具體方法前調(diào)用InvokeHandler來處理。我們通過代理類對象調(diào)用方法時(shí),實(shí)際上會(huì)先調(diào)用其invoke方法,里面再調(diào)用原方法。這樣我們可以在原方法邏輯的前后統(tǒng)一添加處理邏輯。

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

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

Spring AOP注解失效及解決

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

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

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

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

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

解決方法:

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

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

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

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

AOP注解方法里使用@Autowired對象為null

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

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

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

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

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • springboot動(dòng)態(tài)調(diào)用實(shí)現(xiàn)類方式

    springboot動(dòng)態(tài)調(diào)用實(shí)現(xiàn)類方式

    這篇文章主要介紹了springboot動(dòng)態(tài)調(diào)用實(shí)現(xiàn)類方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Java經(jīng)典算法匯總之順序查找(Sequential Search)

    Java經(jīng)典算法匯總之順序查找(Sequential Search)

    Java查找算法之順序查找說明:順序查找適合于存儲(chǔ)結(jié)構(gòu)為順序存儲(chǔ)或鏈接存儲(chǔ)的線性表。 下面我們來詳細(xì)說明下
    2016-04-04
  • Swagger3.0 整合spring boot2.7x避免swagger2.0與boot2.7沖突問題

    Swagger3.0 整合spring boot2.7x避免swagger2.0與boot2.7沖突

    這篇文章主要介紹了Swagger3.0 整合spring boot2.7x避免swagger2.0與boot2.7沖突問題,通過注釋掉2.0引入的倆包,直接引入3.0,文中結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2023-10-10
  • SpringBoot自動(dòng)配置實(shí)現(xiàn)流程詳細(xì)分析

    SpringBoot自動(dòng)配置實(shí)現(xiàn)流程詳細(xì)分析

    這篇文章主要介紹了SpringBoot自動(dòng)配置原理分析,SpringBoot是我們經(jīng)常使用的框架,那么你能不能針對SpringBoot實(shí)現(xiàn)自動(dòng)配置做一個(gè)詳細(xì)的介紹。如果可以的話,能不能畫一下實(shí)現(xiàn)自動(dòng)配置的流程圖。牽扯到哪些關(guān)鍵類,以及哪些關(guān)鍵點(diǎn)
    2022-12-12
  • Java中的流式編程問題

    Java中的流式編程問題

    這篇文章主要介紹了Java中的流式編程問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • 利用java實(shí)現(xiàn)單詞倒序排列

    利用java實(shí)現(xiàn)單詞倒序排列

    這篇文章就是利用java實(shí)現(xiàn)單詞倒序排列,感覺像是在變魔術(shù),感興趣的小伙伴來見證一下
    2015-07-07
  • java實(shí)現(xiàn)用戶自動(dòng)登錄

    java實(shí)現(xiàn)用戶自動(dòng)登錄

    這篇文章主要為大家詳細(xì)介紹了java用戶自動(dòng)登錄的實(shí)現(xiàn)方法,分為六個(gè)步驟實(shí)現(xiàn)用戶自動(dòng)登錄,并驗(yàn)證用戶是否已經(jīng)登錄,感興趣的小伙伴們可以參考一下
    2016-03-03
  • 詳解Java Callable接口實(shí)現(xiàn)多線程的方式

    詳解Java Callable接口實(shí)現(xiàn)多線程的方式

    這篇文章主要介紹了詳解Java Callable接口實(shí)現(xiàn)多線程的方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • java中jdk的下載和安裝全過程

    java中jdk的下載和安裝全過程

    這篇文章主要給大家介紹了關(guān)于java中jdk的下載和安裝的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • Java詳細(xì)講解依賴注入的方式

    Java詳細(xì)講解依賴注入的方式

    Idea中使用@Autowire注解會(huì)出現(xiàn)提示黃線,強(qiáng)迫癥患者看著很難受,使用構(gòu)造器注入或者setter方法注入后可解決,下面我們一起來看看
    2022-06-06

最新評論

延川县| 武鸣县| 丹东市| 星子县| 多伦县| 团风县| 梨树县| 易门县| 海安县| 阳朔县| 石台县| 泉州市| 丰都县| 扶风县| 磴口县| 大城县| 晋州市| 特克斯县| 青川县| 石阡县| 海南省| 军事| 永昌县| 介休市| 云林县| 平谷区| 泾源县| 安吉县| 宣城市| 墨玉县| 壤塘县| 淮南市| 兴城市| 玉树县| 伊吾县| 巴东县| 沛县| 基隆市| 蒲城县| 九台市| 阿克陶县|