日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

cglib动态代理jar包_代理模式详解:静态代理+JDK/CGLIB 动态代理实战

發布時間:2025/3/20 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 cglib动态代理jar包_代理模式详解:静态代理+JDK/CGLIB 动态代理实战 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. 代理模式

代理模式是一種比較好的理解的設計模式。簡單來說就是 我們使用代理對象來代替對真實對象(real object)的訪問,這樣就可以在不修改原目標對象的前提下,提供額外的功能操作,擴展目標對象的功能。

代理模式的主要作用是擴展目標對象的功能,比如說在目標對象的某個方法執行前后你可以增加一些自定義的操作。

舉個例子:你的找了一小紅來幫你問話,小紅就看作是代理我的代理對象,代理的行為(方法)是問話。

https://medium.com/@mithunsasidharan/understanding-the-proxy-design-pattern-5e63fe38052a

代理模式有靜態代理和動態代理兩種實現方式,我們 先來看一下靜態代理模式的實現。

2. 靜態代理

靜態代理中,我們對目標對象的每個方法的增強都是手動完成的(后面會具體演示代碼),非常不靈活(比如接口一旦新增加方法,目標對象和代理對象都要進行修改)且麻煩(需要對每個目標類都單獨寫一個代理類)。 實際應用場景非常非常少,日常開發幾乎看不到使用靜態代理的場景。

上面我們是從實現和應用角度來說的靜態代理,從 JVM 層面來說, 靜態代理在編譯時就將接口、實現類、代理類這些都變成了一個個實際的 class 文件。

靜態代理實現步驟:

  • 定義一個接口及其實現類;
  • 創建一個代理類同樣實現這個接口
  • 將目標對象注注入進代理類,然后在代理類的對應方法調用目標類中的對應方法。這樣的話,我們就可以通過代理類屏蔽對目標對象的訪問,并且可以在目標方法執行前后做一些自己想做的事情。
  • 下面通過代碼展示!

    1.定義發送短信的接口

    public interface SmsService {String send(String message); }

    2.實現發送短信的接口

    public class SmsServiceImpl implements SmsService {public String send(String message) {System.out.println("send message:" + message);return message;} }

    3.創建代理類并同樣實現發送短信的接口

    public class SmsProxy implements SmsService {private final SmsService smsService;public SmsProxy(SmsService smsService) {this.smsService = smsService;}@Overridepublic String send(String message) {//調用方法之前,我們可以添加自己的操作System.out.println("before method send()");smsService.send(message);//調用方法之后,我們同樣可以添加自己的操作System.out.println("after method send()");return null;} }

    4.實際使用

    public class Main {public static void main(String[] args) {SmsService smsService = new SmsServiceImpl();SmsProxy smsProxy = new SmsProxy(smsService);smsProxy.send("java");} }

    運行上述代碼之后,控制臺打印出:

    before method send() send message:java after method send()

    可以輸出結果看出,我們已經增加了 SmsServiceImpl 的send()方法。

    3. 動態代理

    相比于靜態代理來說,動態代理更加靈活。我們不需要針對每個目標類都單獨創建一個代理類,并且也不需要我們必須實現接口,我們可以直接代理實現類( CGLIB 動態代理機制)。

    從 JVM 角度來說,動態代理是在運行時動態生成類字節碼,并加載到 JVM 中的。

    說到動態代理,Spring AOP、RPC 框架應該是兩個不得不的提的,它們的實現都依賴了動態代理。

    動態代理在我們日常開發中使用的相對較小,但是在框架中的幾乎是必用的一門技術。學會了動態代理之后,對于我們理解和學習各種框架的原理也非常有幫助。

    就 Java 來說,動態代理的實現方式有很多種,比如 JDK 動態代理、CGLIB 動態代理等等。

    guide-rpc-framework 使用的是 JDK 動態代理,我們先來看看 JDK 動態代理的使用。

    另外,雖然 guide-rpc-framework 沒有用到 CGLIB 動態代理 ,我們這里還是簡單介紹一下其使用以及和JDK 動態代理的對比。

    3.1. JDK 動態代理機制

    3.1.1. 介紹

    在 Java 動態代理機制中 InvocationHandler 接口和 Proxy 類是核心。

    Proxy 類中使用頻率最高的方法是:newProxyInstance() ,這個方法主要用來生成一個代理對象。

    public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException{......}

    這個方法一共有 3 個參數:

  • loader :類加載器,用于加載代理對象。
  • interfaces : 被代理類實現的一些接口;
  • h : 實現了 InvocationHandler 接口的對象;
  • 要實現動態代理的話,還必須需要實現InvocationHandler 來自定義處理邏輯。 當我們的動態代理對象調用一個方法時候,這個方法的調用就會被轉發到實現InvocationHandler 接口類的 invoke 方法來調用。

    public interface InvocationHandler {/*** 當你使用代理對象調用方法的時候實際會調用到這個方法*/public Object invoke(Object proxy, Method method, Object[] args)throws Throwable; }

    invoke() 方法有下面三個參數:

  • proxy :動態生成的代理類
  • method : 與代理類對象調用的方法相對應
  • args : 當前 method 方法的參數
  • 也就是說:你通過Proxy 類的 newProxyInstance() 創建的代理對象在調用方法的時候,實際會調用到實現InvocationHandler 接口的類的 invoke()方法。 你可以在 invoke() 方法中自定義處理邏輯,比如在方法執行前后做什么事情。

    3.1.2. JDK 動態代理類使用步驟

  • 定義一個接口及其實現類;
  • 自定義 InvocationHandler 并重寫invoke方法,在 invoke 方法中我們會調用原生方法(被代理類的方法)并自定義一些處理邏輯;
  • 通過 Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法創建代理對象;
  • 3.1.3. 代碼示例

    這樣說可能會有點空洞和難以理解,我上個例子,大家感受一下吧!

    1.定義發送短信的接口

    public interface SmsService {String send(String message); }

    2.實現發送短信的接口

    public class SmsServiceImpl implements SmsService {public String send(String message) {System.out.println("send message:" + message);return message;} }

    3.定義一個 JDK 動態代理類

    import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;/*** @author shuang.kou* @createTime 2020年05月11日 11:23:00*/ public class DebugInvocationHandler implements InvocationHandler {/*** 代理類中的真實對象*/private final Object target;public DebugInvocationHandler(Object target) {this.target = target;}public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {//調用方法之前,我們可以添加自己的操作System.out.println("before method " + method.getName());Object result = method.invoke(target, args);//調用方法之后,我們同樣可以添加自己的操作System.out.println("after method " + method.getName());return result;} }

    invoke() 方法: 當我們的動態代理對象調用原生方法的時候,最終實際上調用到的是 invoke() 方法,然后 invoke() 方法代替我們去調用了被代理對象的原生方法。

    4.獲取代理對象的工廠類

    public class JdkProxyFactory {public static Object getProxy(Object target) {return Proxy.newProxyInstance(target.getClass().getClassLoader(), // 目標類的類加載target.getClass().getInterfaces(), // 代理需要實現的接口,可指定多個new DebugInvocationHandler(target) // 代理對象對應的自定義 InvocationHandler);} }

    getProxy() :主要通過Proxy.newProxyInstance()方法獲取某個類的代理對象

    5.實際使用

    SmsService smsService = (SmsService) JdkProxyFactory.getProxy(new SmsServiceImpl()); smsService.send("java");

    運行上述代碼之后,控制臺打印出:

    before method send send message:java after method send

    3.2. CGLIB 動態代理機制

    3.2.1. 介紹

    JDK 動態代理有一個最致命的問題是其只能代理實現了接口的類。

    為了解決這個問題,我們可以用 CGLIB 動態代理機制來避免。

    CGLIB(Code Generation Library)是一個基于ASM的字節碼生成庫,它允許我們在運行時對字節碼進行修改和動態生成。CGLIB 通過繼承方式實現代理。很多知名的開源框架都使用到了CGLIB, 例如 Spring 中的 AOP 模塊中:如果目標對象實現了接口,則默認采用 JDK 動態代理,否則采用 CGLIB 動態代理。

    在 CGLIB 動態代理機制中 MethodInterceptor 接口和 Enhancer 類是核心。

    你需要自定義 MethodInterceptor 并重寫 intercept 方法,intercept 用于攔截增強被代理類的方法。

    public interface MethodInterceptor extends Callback{// 攔截被代理類中的方法public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,MethodProxy proxy) throws Throwable; }
  • obj :被代理的對象(需要增強的對象)
  • method :被攔截的方法(需要增強的方法)
  • args :方法入參
  • methodProxy :用于調用原始方法
  • 你可以通過 Enhancer類來動態獲取被代理類,當代理類調用方法的時候,實際調用的是 MethodInterceptor 中的 intercept 方法。

    3.2.2. CGLIB 動態代理類使用步驟

  • 定義一個類;
  • 自定義 MethodInterceptor 并重寫 intercept 方法,intercept 用于攔截增強被代理類的方法,和 JDK 動態代理中的 invoke 方法類似;
  • 通過 Enhancer 類的 create()創建代理類;
  • 3.2.3. 代碼示例

    不同于 JDK 動態代理不需要額外的依賴。CGLIB(Code Generation Library) 實際是屬于一個開源項目,如果你要使用它的話,需要手動添加相關依賴。

    <dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version> </dependency>

    1.實現一個使用阿里云發送短信的類

    package github.javaguide.dynamicProxy.cglibDynamicProxy;public class AliSmsService {public String send(String message) {System.out.println("send message:" + message);return message;} }

    2.自定義 MethodInterceptor(方法攔截器)

    import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/*** 自定義MethodInterceptor*/ public class DebugMethodInterceptor implements MethodInterceptor {/*** @param o 被代理的對象(需要增強的對象)* @param method 被攔截的方法(需要增強的方法)* @param args 方法入參* @param methodProxy 用于調用原始方法*/@Overridepublic Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {//調用方法之前,我們可以添加自己的操作System.out.println("before method " + method.getName());Object object = methodProxy.invokeSuper(o, args);//調用方法之后,我們同樣可以添加自己的操作System.out.println("after method " + method.getName());return object;}}

    3.獲取代理類

    import net.sf.cglib.proxy.Enhancer;public class CglibProxyFactory {public static Object getProxy(Class<?> clazz) {// 創建動態代理增強類Enhancer enhancer = new Enhancer();// 設置類加載器enhancer.setClassLoader(clazz.getClassLoader());// 設置被代理類enhancer.setSuperclass(clazz);// 設置方法攔截器enhancer.setCallback(new DebugMethodInterceptor());// 創建代理類return enhancer.create();} }

    4.實際使用

    AliSmsService aliSmsService = (AliSmsService) CglibProxyFactory.getProxy(AliSmsService.class); aliSmsService.send("java");

    運行上述代碼之后,控制臺打印出:

    before method send send message:java after method send

    3.3. JDK 動態代理和 CGLIB 動態代理對比

  • JDK 動態代理只能只能代理實現了接口的類,而 CGLIB 可以代理未實現任何接口的類。 另外, CGLIB 動態代理是通過生成一個被代理類的子類來攔截被代理類的方法調用,因此不能代理聲明為 final 類型的類和方法。
  • 就二者的效率來說,大部分情況都是 JDK 動態代理更優秀,隨著 JDK 版本的升級,這個優勢更加明顯。
  • 4. 靜態代理和動態代理的對比

  • 靈活性 :動態代理更加靈活,不需要必須實現接口,可以直接代理實現類,并且可以不需要針對每個目標類都創建一個代理類。另外,靜態代理中,接口一旦新增加方法,目標對象和代理對象都要進行修改,這是非常麻煩的!
  • JVM 層面 :靜態代理在編譯時就將接口、實現類、代理類這些都變成了一個個實際的 class 文件。而動態代理是在運行時動態生成類字節碼,并加載到 JVM 中的。
  • 5. 總結

    這篇文章中主要介紹了代理模式的兩種實現:靜態代理以及動態代理。涵蓋了靜態代理和動態代理實戰、靜態代理和動態代理的區別、JDK 動態代理和 Cglib 動態代理區別等內容。

    文中涉及到的所有源碼,你可以在這里找到:https://github.com/Snailclimb/guide-rpc-framework-learning/tree/master/src/main/java/github/javaguide/proxy 。

    作者:Snailclimb
    鏈接:代理模式詳解:靜態代理+JDK/CGLIB 動態代理實戰
    來源:github

    總結

    以上是生活随笔為你收集整理的cglib动态代理jar包_代理模式详解:静态代理+JDK/CGLIB 动态代理实战的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。