成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

寫給新手!Spring AOP代理機制,必須清楚,否則各種失效

開發 前端
如果要被代理的目標對象實現了至少一個接口,則使用 JDK 動態代理,并且目標類型實現的所有接口都將被代理。如果目標對象沒有實現任何接口,則創建一個 CGLIB 代理,這是一個運行時生成的目標類型的子類。

1. 代理機制

Spring AOP 使用 JDK 動態代理或 CGLIB 來為給定的目標對象創建代理。JDK 動態代理是內置在 JDK 中的,而 CGLIB 是一個常見的開源類定義庫(已重新打包到 spring-core 中)。

如果要被代理的目標對象實現了至少一個接口,則使用 JDK 動態代理,并且目標類型實現的所有接口都將被代理。如果目標對象沒有實現任何接口,則創建一個 CGLIB 代理,這是一個運行時生成的目標類型的子類。

如果你希望強制使用 CGLIB 代理(例如,為了代理目標對象定義的所有方法,而不僅僅是其接口實現的方法),你可以這樣做。但是,你必須考慮以下問題:

  • final修飾的類不能代理,因為它們不能繼承。
  • final修飾的方法不能被增強,因為它們不能被重寫。
  • 私有方法(private methods)無法被增強,因為它們不能被重寫。
  • 不可見的方法(例如,來自不同包的父類中的包私有方法)無法被增強,因為它們實際上是私有的。
  • 你的代理對象的構造函數不會被調用兩次,因為 CGLIB 代理實例是通過 Objenesis(它能繞過構造函數) 創建的。然而,如果你的 JVM 不允許繞過構造函數,你可能會看到兩次調用以及來自 Spring AOP 支持的相應調試日志。
  • 在使用 CGLIB 代理時,你可能會遇到 Java 模塊系統的限制。作為一個典型的例子,當在模塊路徑上部署時,你不能為 java.lang 包中的類創建 CGLIB 代理。這樣的情況需要一個 JVM 啟動標志 --add-opens=java.base/java.lang=ALL-UNNAMED,但該標志對模塊不可用。 

要強制使用 CGLIB 代理,請將 <aop:config> 元素的 proxy-target-class 屬性值設置為 true,如下所示:

<aop:config proxy-target-class="true">
</aop:config>

如果是基于Spring Boot環境,則通過如下配置:

spring:
  aop:
    proxy-target-class: true

該屬性默認值即為true。你還可以使用注解的方式,如下所示:

@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppConfig {}

如果同時配置了,那么自定義注解優先于配置文件。

要在使用 @AspectJ 自動代理支持時強制使用 CGLIB 代理,可以將 <aop:aspectj-autoproxy> 元素的 proxy-target-class 屬性值設置為 true,如下所示:

<aop:aspectj-autoproxy proxy-target-class="true"/>

以上關于代理機制及相關配置的說明。

2. 理解AOP代理

Spring AOP 是基于代理的。在你編寫自己的切面或使用 Spring 框架提供的任何基于 Spring AOP 的切面之前,非常重要的一點是你要理解這句話的實際含義。

首先,請看下面的代碼片段,它顯示了一個普通的、未代理的對象引用:

public class SimplePojo implements Pojo {
  public void foo() {
    this.bar();
  }


  public void bar() {
  }
}

如果你調用一個對象引用上的方法,該方法將直接在該對象引用上被調用,如下圖和列表所示:

圖片圖片

public class Main {


  public static void main(String[] args) {
    Pojo pojo = new SimplePojo();
    pojo.foo();
  }
}

當客戶端代碼的引用是代理時,情況會略有不同。請看下圖和代碼片段:

圖片圖片

public class Main {


  public static void main(String[] args) {
    ProxyFactory factory = new ProxyFactory(new SimplePojo());
    factory.addInterface(Pojo.class);
    factory.addAdvice(new RetryAdvice());


    Pojo pojo = (Pojo) factory.getProxy();
    // 通過創建的代理對象調用
    pojo.foo();
  }
}

這里的關鍵是要理解,main(..) 方法中的客戶端代碼持有一個代理的引用。這意味著對該對象引用的方法調用實際上是調用代理的方法。因此,代理可以委托給與該特定方法調用相關的所有攔截器(通知)。然而,一旦調用到達目標對象(在這個例子中是 SimplePojo ),目標對象上可能進行的任何方法調用,如 this.bar() 或 this.foo(),都將針對 this 引用進行調用,而不是代理。這一點非常重要。這意味著自我調用不會導致與方法調用相關聯的通知有機會運行。換句話說,通過顯式或隱式的 this 引用進行的自我調用將繞過通知。

要解決這個問題,可以通過以下方式:

  • 避免自我調用最好的方法(這里“最好”一詞用得比較寬松)是重構你的代碼,以避免自我調用的發生。這確實需要你做一些工作,但這是最好且侵入性最小的方法。
  • 注入自己另一種方法是使用自我注入(self-injection),并通過自我引用而不是 this 來調用代理上的方法。
  • 使用AopContext.currentProxy()最后這種方法極不推薦。然而,作為最后的手段,你可以選擇將類內的邏輯綁定到 Spring AOP,如下例所示:
public class SimplePojo implements Pojo {


  public void foo() {
    ((Pojo) AopContext.currentProxy()).bar() ;
  }
  public void bar() {
  }
}

使用 AopContext.currentProxy() 完全將你的代碼耦合到 Spring AOP,并使類本身意識到它正在一個 AOP 上下文中使用,這減少了 AOP 的一些好處。同時你還需要進行如下的配置才能使用如上方法:

public class Main {


  public static void main(String[] args) {
    ProxyFactory factory = new ProxyFactory(new SimplePojo());
    factory.addInterface(Pojo.class);
    factory.addAdvice(new RetryAdvice());
    // 必須設置為true,你才能調用上面的方法
    factory.setExposeProxy(true);


    Pojo pojo = (Pojo) factory.getProxy() ;
    pojo.foo();
  }
}

如果你是Spring Boot環境,那么你可以通過下面的方式進行設置:

@EnableAspectJAutoProxy(exposeProxy = true)
public class AppConfig {}

以上內容,對于我們學習使用AOP新手來說必須要知道及掌握的內容,這樣可以盡可能的減少錯誤的發生。

責任編輯:武曉燕 來源: Spring全家桶實戰案例源碼
相關推薦

2024-01-29 08:28:01

Spring事務失效

2012-05-01 21:27:20

iOS

2021-03-04 08:06:13

Java代理機制

2022-09-01 10:40:29

SpringAOPJDK

2024-04-01 08:38:57

Spring@AspectAOP

2018-08-03 12:52:51

首頁彈窗iOS

2018-08-08 20:35:58

APP結構指南導航

2023-10-08 10:14:12

2023-08-02 10:48:47

SpringBean反射

2009-06-19 13:28:30

Spring AOPSpring 2.0

2022-06-07 07:58:45

SpringSpring AOP

2011-06-13 17:43:37

SEO建站

2018-09-03 12:39:41

信息架構設計產品

2025-02-26 13:13:52

2009-06-22 10:41:34

Spring.AOP

2013-05-22 15:31:07

AOP的CGlib實現

2015-08-14 13:51:22

程序員

2022-02-17 13:39:09

AOP接口方式

2019-05-10 10:50:04

Spring AOPJDK動態代理CGLIB動態代理

2022-06-08 08:04:28

Springservicerepository
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产一级特黄真人毛片 | 国产精品国产a | 午夜精品久久 | 在线观看视频一区 | 国产精品揄拍一区二区 | 欧美一级欧美一级在线播放 | 国产黄色在线观看 | 欧美日韩高清 | 一区二区视频在线 | 欧美一卡二卡在线 | 视频在线一区二区 | 91精品国产美女在线观看 | 久久狠狠 | 在线亚洲免费视频 | 男女羞羞视频免费看 | 亚洲一区二区精品视频 | www.久久久久久久久 | 九九免费观看视频 | 欧美精品一区在线 | 台湾a级理论片在线观看 | www.色综合 | 久久高清国产视频 | 国产成人精品一区二区 | 三级黄片毛片 | 韩三级在线观看 | 日韩国产黄色片 | 伊人免费网 | 911精品国产 | 久综合| 黑人一级黄色大片 | 视频一区 亚洲 | 免费在线成人 | 精品国产一区二区三区四区在线 | 97人人超碰 | 国产精品久久午夜夜伦鲁鲁 | 亚洲视频在线看 | 精品久久成人 | 自拍偷拍av | 国产精品毛片av一区 | 黄色一级片视频 | 午夜精品久久 |