代理
指的是代表授權(quán)方執(zhí)行處理事務(wù)。在編程中,通常是通過一個(gè)代理對象代表目標(biāo)對象去執(zhí)行方法,是對調(diào)用目標(biāo)的一個(gè)包裝。這樣來保證目標(biāo)對象方法的安全性、或者增強(qiáng)目標(biāo)對象的方法功能。
Java 有 3 種代理方式:
靜態(tài)代理
通過手動創(chuàng)建代理對象,來實(shí)現(xiàn)對目標(biāo)對象的代理。在這過程中,一般存在 3 種對象:客戶端、目標(biāo)對象、代理對象。
客戶端通過代理對象去調(diào)用目標(biāo)對象的真實(shí)方法。
對象的接口
public interface IService {
void request();
}
真正的目標(biāo)對象
public class RealService implements IService {
@Override
public void request() {
System.out.println("真正處理請求內(nèi)容");
}
}
代理類
public class ProxyService implements IService {
private IService realService;
public ProxyService(IService service) {
this.realService = service;
}
@Override
public void request() {
// ...執(zhí)行真實(shí) request() 前其他邏輯
System.out.println("request() 方法前邏輯");
this.realService.request();
System.out.println("request() 方法后邏輯");
// ...執(zhí)行真實(shí) request() 后其他邏輯
}
}
客戶端實(shí)現(xiàn)
public class StaticProxyClient {
public void callRequest() {
// 目標(biāo)對象
IService realService = new RealService();
// 代理對象
IService proxyService = new ProxyService(realService);
// 通過代理對象執(zhí)行真正的邏輯,并且在代理對象中對請求進(jìn)行增強(qiáng)
proxyService.request();
}
}
靜態(tài)代理需要手動地為每個(gè)目標(biāo)類創(chuàng)建代理類,而代理類中的邏輯都是類似的簡單的,為了更簡單地使用代理出現(xiàn)了動態(tài)代理,通過在運(yùn)行期動態(tài)創(chuàng)建接口對象的代理,避免了手動去創(chuàng)建靜態(tài)代理類。
動態(tài)代理是在運(yùn)行時(shí)動態(tài)生成的,即編譯完成后沒有實(shí)際的 class 文件,而是在運(yùn)行時(shí)動態(tài)生成類字節(jié)碼,并加載到 JVM 中。
JDK 原生動態(tài)代理
JDK 提供了 Proxy.newProxyInstance() 來創(chuàng)建動態(tài)代理。實(shí)現(xiàn)步驟如下:
- 創(chuàng)建被代理的目標(biāo)類及它的接口
- 創(chuàng)建接口 InvocationHandler 的實(shí)現(xiàn)類,它必須實(shí)現(xiàn) invoke 方法
- 通過 Proxy 的靜態(tài)方法 newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 創(chuàng)建一個(gè)代理對象
- 通過代理對象調(diào)用方法,代理的方法會被 InvocationHandler 的實(shí)現(xiàn)類接管
// 實(shí)現(xiàn) InvocationHandler 類,它的 invoke() 方法會接管代理調(diào)用的方法
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理方法前邏輯");
Object result = method.invoke(this.target, args);
System.out.println("代理方法后邏輯");
return result;
}
}
// JDK 動態(tài)代理測試
public class JDKDynamicProxyClient {
public static void main(String[] args) {
RealService realService = new RealService();
InvocationHandler handler = new MyInvocationHandler(realService);
IService service = (IService) Proxy.newProxyInstance(
// 通常是接口類的 ClassLoader
IService.class.getClassLoader(),
// 要實(shí)現(xiàn)的接口數(shù)組
new Class[]{IService.class},
// 代理用來處理調(diào)用方法的 InvocationHandler
handler
);
// 通過代理類調(diào)用方法
service.request();
}
}
原理分析
主要是看 Proxy.newProxyInstance()
方法。
- Proxy 類的靜態(tài)變量加載時(shí)初始化 proxyClassCache,代理類緩存中初始化代理類的創(chuàng)建工廠為 ProxyClassFactory()
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
- Proxy.newProxyInstance() 靜態(tài)方法返回代理類對象,它的調(diào)用過程如下:
Proxy.newProxyInstance()
Proxy.getProxyClass0()
ProxyClassFactory.get() #先從代理類緩存中查詢,沒有時(shí)從代理類工廠中創(chuàng)建
ProxyClassFactory.apply() #代理類工廠創(chuàng)建
ProxyGenerator.generateProxyClass() #代理類生成器,生成代理類代碼
ProxyClassFactory.defineClass0() #加載生成的 class 文件到 jvm,java 接著就能調(diào)用了
最終生成的代理類關(guān)鍵代碼如下:
// 代理類繼承 Proxy 類,并實(shí)現(xiàn) IService 接口
// 代理類名稱固定位 "com.sun.proxy.$Proxy"+自增數(shù)字
public final class com.sun.proxy.$Proxy0 extends Proxy implements IService {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
// 構(gòu)造函數(shù)中設(shè)置代理類的 InvocationHandler
public com.sun.proxy.$Proxy0(InvocationHandler var1) throws {
super(var1);
}
// ...
public final void request() throws {
try {
// 實(shí)際是 handler 中調(diào)用目標(biāo)類的方法
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
// 代理的方法
m3 = Class.forName("proxy.IService").getMethod("request");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
當(dāng)代理執(zhí)行到 request() 方法時(shí),實(shí)際執(zhí)行的是 InvocationHandler 的 invoke() 方法,并在方法中通過反射調(diào)用目標(biāo)類的真實(shí)方法。
JDK 動態(tài)代理要求被代理的對象必須有對應(yīng)的一個(gè)或多個(gè)接口,不能給原類生成動態(tài)代理類。
CGLIB 動態(tài)代理
CGLIB 是一個(gè)強(qiáng)大的高性能代碼生成包,可以在運(yùn)行期轉(zhuǎn)換字節(jié)碼并生成目標(biāo)類的子類。
CGLIB 創(chuàng)建代理類對象是通過 Enhancer 類實(shí)現(xiàn)的,創(chuàng)建代理的主要步驟:
- 創(chuàng)建被代理的目標(biāo)類
- 創(chuàng)建 Enchaner 類對象,設(shè)置對象的父類(為被代理的目標(biāo)類)及 Callback 對象,通過 Enchaner 類的 create() 方法創(chuàng)建代理類對象
- 通過代理對象調(diào)用方法
// 被代理的類不需要實(shí)現(xiàn)接口,但是被代理的方法和類不能是 final
public class RequestService {
public void request() {
System.out.println("真正處理請求內(nèi)容");
}
}
// CGLIB 代理測試
public class CGLIBProxyClient {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(RequestService.class);
// 這里是一個(gè)匿名類,被代理方法的處理類,需要實(shí)現(xiàn) MethodInterceptor 接口的 intercept 方法
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects,
MethodProxy methodProxy) throws Throwable {
System.out.println("真實(shí)方法前邏輯...");
methodProxy.invokeSuper(o, objects);
System.out.println("真實(shí)方法后邏輯...");
return null;
}
});
RequestService requestService = (RequestService) enhancer.create();
requestService.request();
}
}
在項(xiàng)目中通過增加下面設(shè)置,可以將生成的動態(tài)類保存到代碼的根目錄
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "./");
運(yùn)行創(chuàng)建代理后,就可以在項(xiàng)目根目錄中看到 enhancer.create 創(chuàng)建的動態(tài)類,它的關(guān)鍵代碼如下:
// 繼承目標(biāo)類 RequestService
public class RequestService$$EnhancerByCGLIB$$6a2da525 extends RequestService implements Factory {
// 重寫了 request() 方法
public final void request() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
// enhancer.setCallback() 已經(jīng)設(shè)置 callback,所以這里不為空
if (var10000 != null) {
// 調(diào)用 callback 中實(shí)現(xiàn)的 intercept() 方法
var10000.intercept(this, CGLIB$request$0$Method, CGLIB$emptyArgs, CGLIB$request$0$Proxy);
} else {
super.request();
}
}
}
在 Callback 中通過 methodProxy.invokeSuper(o, objects);
來調(diào)用目標(biāo)類的方法
public class MethodProxy {
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
// 初始化代理類、目標(biāo)類信息
// fci.f2 為代理類; fci.i2 為代理類中的代理方法的方法下標(biāo)
init();
FastClassInfo fci = fastClassInfo;
// 代理類通過下標(biāo)調(diào)用代理方法
return fci.f2.invoke(fci.i2, obj, args);
}
catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
}
自動生成的 FastClass 類主要代碼如下:
// 繼承 FastClass 類
public class RequestService$$FastClassByCGLIB$$86d56cc6 extends FastClass {
// 根據(jù)方法簽名的 hash 值映射方法的下標(biāo)
public int getIndex(String var1, Class[] var2) {
switch(var1.hashCode()) {
// ...
case 1095692943:
if (var1.equals("request")) {
switch(var2.length) {
case 0:
return 0;
}
}
}
return -1;
}
// 代理類實(shí)際調(diào)用的地方,通過代理方法的下標(biāo)調(diào)用目標(biāo)類方法(不是反射方式)
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
RequestService var10000 = (RequestService)var2;
int var10001 = var1;
try {
switch(var10001) {
case 0:
var10000.request();
return null;
case 1:
return new Boolean(var10000.equals(var3[0]));
case 2:
return var10000.toString();
case 3:
return new Integer(var10000.hashCode());
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
}
最后
有問題,歡迎留言交流
參考內(nèi)容
https://time.geekbang.org/column/article/10076
https://zhuanlan.zhihu.com/p/35144462