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

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

JDK動態代理spring

JDK 1.3版本之後提供了動態代理,容許開發者在運行期建立接口的代理實例,並且只能爲接口建立代理實例。
若是被代理目標沒有接口那麼Spring也無能爲力,Spring經過Java的反射機制生成被代理接口的新的匿名實現類。編程

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

  1. 經過實現InvocationHandlet接口建立本身的調用處理器;性能

  2. 經過爲Proxy類指定ClassLoader對象和一組interface來建立動態代理;代理

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

  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;
}
相關文章
相關標籤/搜索