Spring AOP動態代理實現,解決Spring Boot中無法正常啟用JDK動態代理的問題


Spring AOP底層的動態代理實現有兩種方式:一種是JDK動態代理,另一種是CGLib動態代理。

JDK動態代理

JDK 1.3版本以后提供了動態代理,允許開發者在運行期創建接口的代理實例,而且只能為接口創建代理實例。
如果被代理目標沒有接口那么Spring也無能為力,Spring通過Java的反射機制生成被代理接口的新的匿名實現類。

JDK動態代理具體實現原理:

  1. 通過實現InvocationHandlet接口創建自己的調用處理器;

  2. 通過為Proxy類指定ClassLoader對象和一組interface來創建動態代理;

  3. 通過反射機制獲取動態代理類的構造函數,其唯一參數類型就是調用處理器接口類型;

  4. 通過構造函數創建動態代理類實例,構造時調用處理器對象作為參數參入;

CGLib動態代理

CGLib 全稱 Code Generation Library,是一個強大的高性能字節碼生成類庫,可以實現運行期動態擴展Java類。
Spring在運行期采用CGLib的字節碼技術為類創建一個子類,並在子類中攔截所有父類方法的調用,織入橫切邏輯實現AOP面向切面編程。

注意事項

如果被代理的對象實現了接口,那么Spring默認會使用JDK動態代理,否則會強制使用CGLib實現動態代理(如果被代理的類被final關鍵字所修飾,那么代理會失敗)

關於兩者的性能,JDK動態代理所創建的代理對象,在1.8以前的版本中性能並不高,最新版本中性能得到了很大的提升,和CGLib相差不大。

Spring Boot中無法正常啟用JDK動態代理的問題

關於Spring的默認動態代理模式,官方文檔中顯示是JDK動態代理,但Spring Boot 2.2中發現即使強制指定@EnableAspectJAutoProxy(proxyTargetClass = false) ,生成的代理類依然顯示$EnhancerBySpringCGLIB。

DefaultAopProxyFactory中發現isProxyTargetClass被指定為強制代理目標類,所以會采用ObjenesisCglibAopProxy創建代理。

最后跟蹤到ValidationAutoConfiguration中的一個Bean方法中,主動讀取了環境變量spring.aop.proxy-target-class,而且默認值是true。
問題點算是找到了,不過這里只是一個函數校驗的處理器,竟然會強制讀取魔法配置,有些莫名其妙...手工添加配置后JDK代理恢復正常。

@Bean
@ConditionalOnMissingBean
public static MethodValidationPostProcessor methodValidationPostProcessor(Environment environment, @Lazy Validator validator) {
    MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
    boolean proxyTargetClass = environment.getProperty("spring.aop.proxy-target-class", Boolean.class, true);
    processor.setProxyTargetClass(proxyTargetClass);
    processor.setValidator(validator);
    return processor;
}


免責聲明!

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



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