Java 代理模式
使用代理對象來代替對真實對象(real object)的訪問,這樣就可以在不修改原目標對象的前提下,提供額外的功能操作,擴展目標對象的功能
靜態代理
靜態代理在編譯時就將接口、實現類、代理類這些都變成了一個個實際的 class 文件
public interface SmsService {public void send(String message);
}class SmsServiceImpl implements SmsService{@Overridepublic void send(String message) {System.out.println("message :"+message);}
}class SmsServiceProxy implements SmsService{private SmsService smsService;public SmsServiceProxy(SmsService smsService){this.smsService = smsService;}@Overridepublic void send(String message) {System.out.println("輸出消息前");smsService.send(message);System.out.println("輸出消息后");}public static void main(String[] args) {SmsServiceImpl smsService = new SmsServiceImpl();SmsServiceProxy smsServiceProxy = new SmsServiceProxy(smsService);smsServiceProxy.send("這是個消息");/* 輸出消息前message :這是個消息 輸出消息后*/}
}
動態代理
從 JVM 角度來說,動態代理是在運行時動態生成類字節碼,并加載到 JVM 中的
JDK 動態代理機制
在 Java 動態代理機制中 InvocationHandler
接口和 Proxy
類是核心
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException{......}
- loader :類加載器,用于加載代理對象。
- interfaces : 被代理類實現的一些接口;
- h : 實現了
InvocationHandler
接口的對象;
public interface InvocationHandler {/*** 當你使用代理對象調用方法的時候實際會調用到這個方法*/public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
}
- proxy :動態生成的代理類
- method : 與代理類對象調用的方法相對應
- args : 當前 method 方法的參數
通過Proxy
類的 newProxyInstance()
創建的代理對象在調用方法的時候,實際會調用到實現InvocationHandler
接口的類的 invoke()
方法。
你可以在 invoke()
方法中自定義處理邏輯,比如在方法執行前后做什么事情
CGLIB 動態代理機制
JDK 動態代理有一個最致命的問題是其只能代理實現了接口的類,為了解決這個問題 CGLIB 動態代理機制來避免
在 CGLIB 動態代理機制中 MethodInterceptor
接口和 Enhancer
類是核心
public interface MethodInterceptor
extends Callback{// 攔截被代理類中的方法public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,MethodProxy proxy) throws Throwable;
}
- obj : 被代理的對象(需要增強的對象)
- method : 被攔截的方法(需要增強的方法)
- args : 方法入參
- proxy : 用于調用原始方法
通過 Enhancer
類來動態獲取被代理類,當代理類調用方法的時候,實際調用的是 MethodInterceptor
中的 intercept
方法
JDK 動態代理和 CGLIB 動態代理對比
- JDK 動態代理只能代理實現了接口的類或者直接代理接口,而 CGLIB 可以代理未實現任何接口的類。 另外, CGLIB 動態代理是通過生成一個被代理類的子類來攔截被代理類的方法調用,因此不能代理聲明為 final 類型的類和方法。
- 就二者的效率來說,大部分情況都是 JDK 動態代理更優秀,隨著 JDK 版本的升級,這個優勢更加明顯。
靜態代理和動態代理的對比
- 靈活性
- JVM 層面