Java中代理模式的幾種實現方式詳細技術解析

代理模式在Java中主要有四種實現方式。1. 靜態代理需手動編寫代理類,通過持有目標類引用并添加額外邏輯,適合小規模項目但代碼冗余;2. jdk動態代理基于接口,利用proxy和invocationhandler在運行時生成代理對象,靈活但僅限接口代理;3. cglib代理通過繼承目標類并重寫方法實現,可代理無接口類,適用范圍廣但無法處理final類或方法;4. spring aop根據目標類是否實現接口自動選擇jdk或cglib代理,也可強制使用cglib,使開發者無需關注底層實現。

Java中代理模式的幾種實現方式詳細技術解析

代理模式在Java中是一種常見的設計模式,主要用于控制對象的訪問、增強功能或延遲加載。它通過一個代理類來間接操作目標對象,常用于AOP編程、遠程調用(RMI)、權限控制等場景。

Java中代理模式的幾種實現方式詳細技術解析

Java中實現代理的方式有多種,下面從常見且實用的角度出發,分別介紹幾種主流的代理實現方式。

Java中代理模式的幾種實現方式詳細技術解析


靜態代理:手動編寫代理類

靜態代理是最基礎也是最容易理解的一種代理方式。它的特點是需要為每一個目標類手動編寫一個對應的代理類。

立即學習Java免費學習筆記(深入)”;

實現步驟如下:

Java中代理模式的幾種實現方式詳細技術解析

  • 定義一個公共接口
  • 實現目標類
  • 編寫代理類,持有目標類的引用,并在其方法前后添加額外邏輯

舉個例子:

public interface Service {     void doSomething(); }  public class RealService implements Service {     public void doSomething() {         System.out.println("Doing something...");     } }  public class StaticProxy implements Service {     private Service target;      public StaticProxy(Service target) {         this.target = target;     }      public void doSomething() {         System.out.println("Before method call");         target.doSomething();         System.out.println("After method call");     } }

這種方式優點是結構清晰,缺點是代碼冗余,每增加一個服務都需要一個新的代理類。


JDK動態代理:基于接口的運行時代理生成

JDK動態代理是Java自帶的功能,利用java.lang.reflect.Proxy類和InvocationHandler接口實現在運行時動態創建代理對象。

關鍵點在于:

  • 目標類必須實現至少一個接口
  • 通過Proxy.newProxyInstance()方法生成代理實例
  • 所有對代理對象的方法調用都會轉發到invoke()方法中處理

示例代碼:

Service proxy = (Service) Proxy.newProxyInstance(     Service.class.getClassLoader(),     new Class[]{Service.class},     new InvocationHandler() {         private Object target = new RealService();          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {             System.out.println("JDK Proxy: before");             Object result = method.invoke(target, args);             System.out.println("JDK Proxy: after");             return result;         }     } );  proxy.doSomething();

這種方式的優點是靈活性高,無需手動編寫代理類。但局限也很明顯:只能對接口進行代理,不能代理沒有實現接口的類。


CGLIB代理:基于繼承的字節碼增強

CGLIB是一個強大的第三方庫,它通過繼承目標類并重寫其方法的方式來生成代理類,因此可以代理沒有實現接口的類。

使用CGLIB的關鍵組件是Enhancer類和MethodInterceptor接口。

基本流程如下:

  1. 創建Enhancer實例
  2. 設置父類(即目標類)
  3. 設置回調函數(即攔截器)
  4. 調用create()方法生成代理對象

簡單示例:

Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(RealService.class); enhancer.setCallback(new MethodInterceptor() {     public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {         System.out.println("CGLIB Proxy: before");         Object result = proxy.invokeSuper(obj, args);         System.out.println("CGLIB Proxy: after");         return result;     } });  RealService proxy = (RealService) enhancer.create(); proxy.doSomething();

CGLIB適用于更廣泛的場景,尤其適合Spring這類框架中默認使用的代理機制。但要注意的是,不能代理final類和final方法。


Spring AOP中的代理機制:自動選擇JDK或CGLIB

在實際開發中,我們經常使用Spring AOP來實現日志記錄、事務管理等功能。Spring底層會根據目標類是否實現了接口來自動選擇使用JDK動態代理還是CGLIB代理。

Spring的判斷邏輯大致如下:

  • 如果目標類實現了至少一個接口,優先使用JDK動態代理
  • 否則使用CGLIB代理

當然你也可以強制Spring始終使用CGLIB代理,只需在配置中設置:

<aop:config proxy-target-class="true"/>

或者在注解驅動下啟用:

@EnableAspectJAutoProxy(proxyTargetClass = true)

這種機制讓開發者不需要關心底層代理是如何構建的,只需要專注于切面邏輯的編寫即可。


總的來說,Java中代理模式的實現方式各有適用場景。靜態代理適合小規模項目或教學用途;JDK動態代理和CGLIB代理則更適合實際開發中靈活擴展的需求;而Spring在此基礎上進一步封裝,使得代理機制對開發者透明化。

基本上就這些。

? 版權聲明
THE END
喜歡就支持一下吧
點贊7 分享