天天看點

spring jdk動态代理、Cglib動态代理和LoadTimeWeaver(LTW)的應用選擇

在Java 語言中,從織入切面的方式上來看,存在三種織入方式:編譯期織入、類加載期織入和運作期織入。編譯期織入是指在Java編譯期,采用特殊的編譯器,将切面織入到Java類中;而類加載期織入則指通過特殊的類加載器,在類位元組碼加載到JVM時,織入切面;運作期織入則是采用CGLib工具或JDK動态代理進行切面的織入。 

AspectJ采用編譯期織入和類加載期織入的方式織入切面,是語言級的AOP實作,提供了完備的AOP支援。它用AspectJ語言定義切面,在編譯期或類加載期将切面織入到Java類中。 

AspectJ提供了兩種切面織入方式,第一種通過特殊編譯器,在編譯期,将AspectJ語言編寫的切面類織入到Java類中,可以通過一個Ant或Maven任務來完成這個操作;第二種方式是類加載期織入,也簡稱為LTW(Load Time Weaving)。 

如何使用Load Time Weaving?首先,需要通過JVM的-javaagent參數設定LTW的織入器類包,以代理JVM預設的類加載器;第二,LTW織入器需要一個 aop.xml檔案,在該檔案中指定切面類和需要進行切面織入的目标類。

在做spring項目時,如果代理對象是單例模式,選擇cglib動态代理;如果是prototype模式,選擇jdk動态代理。

一般不會用到Load Time Weaving代理。

但是,一些特殊情況jdk和cglib動态代理也有局限性,一些特殊情況隻能選擇Load Time Weaving代理。

jdk動态代理的局限:

因為jdk代理是 基于接口的動态代理技術,由于接口的方法都必然是public的,這就要求實作類的實作方法也必須是public的(不能是 protected、private等),同時不能使用static的修飾符。是以,可以實施jdk動态代理的方法隻能使用public或public final修飾符的方法,其他方法不可能被動态代理,相應的也就不能實施AOP增強,換句話,即不能進行spring 增強了。

Cglib動态代理的局限:

基于Cglib位元組碼動态代理是通過擴充被增強類,動态建立其子類的方式進行AOP增強植入的。由于使用final、static、private修飾符的方法不能被子類覆寫,相應的,這些方法就無法實施AOP增強。

總結:jdk動态代理建立時效率比cglib高,但執行效率比cglib低。是以如果代理對象是單例模式,選擇cglib動态代理;如果是prototype模式,選擇jdk動态代理。

當遇到jdk和cglib代理局限性無法解決問題時,可以選擇Load Time Weaving代理。

至于,aspectj 的Load Time Weaving技術的效率,沒研究過,請大牛解惑。