一、proxy-target-class概念介紹
在Spring框架中,AOP被廣泛用於各種類型的應用程序,用於將橫切關注點與業務邏輯相分離,以提高應用程序的靈活性和可重用性。 Spring Framework通過動態代理或CGLIB庫實現了AOP。 Spring AOP支持兩種類型的代理:介面代理(默認情況下)和基於類的代理(使用proxy-target-class屬性)。 介面代理要求目標對象實現至少一個介面。 基於類的代理(一般使用CGLIB庫)則無需介面。相反,它們使用位元組代碼生成來創建目標對象的代理。 建議在以下情況下使用基於類的代理:
• 目標對象不實現任何介面
• 要從代理方法中調用另一個方法而不添加太多額外的代碼,這可能是使用AOP的一個常見要求
• 希望代理位置更快(默認情況下,介面代理通常比基於類的代理慢)
二、proxy-target-class屬性用法
Spring框架中提供了兩種代理方式proxy-target-class和proxy-interface。proxy-target-class默認值為false,代表使用基於介面的JDK動態代理,此時目標對象的實現類必須至少實現一個介面;而如果proxy-target-class設置為true,則使用CGLIB方式的動態代理。
使用proxy-target-class的時候,目標類不需要實現任何介面也能被AOP代理攔截,Spring會選擇CGLIB代理方式生成動態代理對象。
下面是具體的proxy-target-class使用示例
@Configuration @EnableAspectJAutoProxy(proxyTargetClass = true) public class AppConfig { @Bean public MyAspect myAspect() { return new MyAspect(); } @Bean public UserService userService() { return new UserServiceImpl(); } }
可以看到,通過@EnableAspectJAutoProxy(proxyTargetClass = true)開啟CGLIB代理,默認為false,開啟CGLIB代理需要導入CGLIB庫。
三、CGLIB與JDK動態代理的區別
基於類的代理(即CGLIB)通常比基於介面的代理(即JDK)更快,因為它們直接操作位元組碼。但是,CGLIB不適用於代理類中的final方法 – 您不能在CGLIB類中覆蓋final方法。 此外,使用CGLIB可能會將代理類的大小從一個介面代理的62位元組增加到100位元組或更多,而增加的碼元數量可能對某些JIT編譯器效果不佳。
下面是一個基於類的代理的簡單示例
public class HelloWorld { public void sayHello(String name) { System.out.println("Hello " + name); } public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(HelloWorld.class); enhancer.setCallback(new MethodInterceptorImpl()); HelloWorld proxy = (HelloWorld) enhancer.create(); proxy.sayHello("World"); } } class MethodInterceptorImpl implements MethodInterceptor { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("Before Method Invocation"); Object returnObj = proxy.invokeSuper(obj, args); System.out.println("After Method Invocation"); return returnObj; } }
四、proxy-target-class的使用場景
proxy-target-class屬性的最主要的使用場景就是處理沒有實現任何介面的獨立類的AOP。在Java中,我們往往缺乏混入委託等支持多重繼承的特性,導致同一個對象分支下的邏輯散佈於不同類中,這就是所謂的橫切關注點。AOP可以解決這個問題,而對於沒有實現介面的類來說,proxy-target-class就派上用場了。
五、總結
在Spring AOP中,默認情況下使用基於介面的動態代理,可以通過配置proxy-target-class屬性來選擇使用CGLIB提供的基於類的動態代理。對於那些不實現任何介面的類來說,proxy-target-class是必不可少的。
最後,需要注意的是,應謹慎使用proxy-target-class屬性,在大型應用程序中或需要高性能的場景中,建議使用基於介面的動態代理來提高系統的性能。
原創文章,作者:WCKUW,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/317803.html