Spring 5 AOP 代理對象方式默認改用 CGLIB 了嗎?


1. 真的假的?查閱文檔

剛看到這個說法的時候,我是保持懷疑態度的。

大家都知道 Spring5 之前的版本 AOP 在默認情況下是使用 JDK 動態代理的,那是不是 Spring5 版本真的做了修改呢?於是我打開 Spring Framework 5.x 文檔,再次確認了一下:

文檔地址:https://docs.spring.io/spring/docs/5.2.0.RELEASE/spring-framework-reference/core.html#aop

 

簡單翻譯一下。Spring AOP 默認使用 JDK 動態代理,如果對象沒有實現接口,則使用 CGLIB 代理。當然,也可以強制使用 CGLIB 代理。也就是沒有改變

 

 

2 .SpringBoot 2.x 代碼示例

public interface ClassInterE{
    public void funA();
}

@Component
public class ClassSonE implements ClassInterE{
    @Transactional
    public void funA(){}
    public void funB(){}
}

 

 

 

ClassSonE實現了ClassInterE接口,同時使用@Transactional對ClassSonE#funA方法進行前置增強攔截。

從運行結果來看,這里的確使用了 CGLIB 代理而不是 JDK 動態代理。

難道真的是文檔寫錯了?!

 

@EnableAspectJAutoProxy 源碼注釋

在 Spring Framework 中,是使用@EnableAspectJAutoProxy注解來開啟 Spring AOP 相關功能的。Spring Framework 5.2.0.RELEASE 版本@EnableAspectJAutoProxy注解源碼如下:

 

 

 通過源碼注釋我們可以了解到:在 Spring Framework 5.2.0.RELEASE 版本中,proxyTargetClass的默認取值依舊是false,默認還是使用 JDK 動態代理。難道文檔和源碼注釋都寫錯了?!

Spring Framework 5.x 整理一下思路

  1. 有人說 Spring5 開始 AOP 默認使用 CGLIB 了
  2. Spring Framework 5.x 文檔和  @EnableAspectJAutoProxy源碼注釋都說了默認是使用 JDK 動態代理
  3. 程序運行結果說明,即使繼承了接口,設置 proxyTargetClass為 false,程序依舊使用 CGLIB 代理

3 . 示例程序是使用 SpringBoot 來運行的,那如果不用 SpringBoot,只用 Spring Framework 會怎么樣呢?

 

 

 運行結果表明:在 Spring Framework 5.x 版本中,如果類實現了接口,AOP 默認還是使用 JDK 動態代理。

 

再探 SpringBoot 2.x

  1. Spring5 AOP 默認依舊使用 JDK 動態代理,官方文檔和源碼注釋沒有錯。
  2. SpringBoot 2.x 版本中,AOP 默認使用 cglib,且無法通過 proxyTargetClass進行修改。
  3. 那是不是 SpringBoot 2.x 版本做了一些改動呢?

源碼分析

源碼分析,找對入口很重要。那這次的入口在哪里呢?

@SpringBootApplication是一個組合注解,該注解中使用@EnableAutoConfiguration實現了大量的自動裝配。

EnableAutoConfiguration也是一個組合注解,在該注解上被標志了@Import。關於@Import注解的詳細用法,可以參看筆者之前的文章:https://mp.weixin.qq.com/s/7arh4sVH1mlHE0GVVbZ84Q

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}

在 Spring Framework 4.x 版本中,這是一個空接口,它僅僅是繼承了ImportSelector接口而已。而在 5.x 版本中拓展了DeferredImportSelector接口,增加了一個getImportGroup方法:

 

在這個方法中返回了AutoConfigurationGroup類。這是AutoConfigurationImportSelector中的一個內部類,他實現了DeferredImportSelector.Group接口。

在 SpringBoot 2.x 版本中,就是通過AutoConfigurationImportSelector.AutoConfigurationGroup#process方法來導入自動配置類的。

 

 

通過斷點調試可以看到,和 AOP 相關的自動配置是通過org.springframework.boot.autoconfigure.aop.AopAutoConfiguration來進行配置的。

 

 

真相大白

看到這里,可以說是真相大白了。在 SpringBoot2.x 版本中,通過AopAutoConfiguration來自動裝配 AOP。

默認情況下,是肯定沒有spring.aop.proxy-target-class這個配置項的。而此時,在 SpringBoot 2.x 版本中會默認使用 Cglib 來實現。

 

5. SpringBoot 2.x 中如何修改 AOP 實現

通過源碼我們也就可以知道,在 SpringBoot 2.x 中如果需要修改 AOP 的實現,需要通過spring.aop.proxy-target-class這個配置項來修改。

#在application.properties文件中通過spring.aop.proxy-target-class來配置
spring.aop.proxy-target-class=false

 

 

總結

  1. Spring 5.x 中 AOP 默認依舊使用 JDK 動態代理。
  2. SpringBoot 2.x 開始,為了解決使用 JDK 動態代理可能導致的類型轉化異常而默認使用 CGLIB。
  3. 在 SpringBoot 2.x 中,如果需要默認使用 JDK 動態代理可以通過配置項 spring.aop.proxy-target-class=false來進行修改, proxyTargetClass配置已無效。

 


免責聲明!

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



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