Java動態代理實現原理淺析
程式碼編寫
- 介面編寫
public interface TargetInterface {
void targetMethod();
} - 實現類編寫
public class Target implements TargetInterface {
@Override
public void targetMethod() {
System.out.println("target method invoking ...");
}
} - 增強類編寫
public class ProxyHandler implements InvocationHandler {
private Object proxyTarget;
public ProxyHandler(Object proxyTarget) {
this.proxyTarget = proxyTarget;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("do somethings before target method invoke");
Object result = method.invoke(proxyTarget, args);
System.out.println("do somethings after target method invoke");
return result;
}
} - 測試類編寫
public class ProxyTest {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getContextClassLoader());
TargetInterface target = new Target();
ClassLoader loader = target.getClass().getClassLoader();
Class<?>[] interfaces = target.getClass().getInterfaces();
InvocationHandler proxyHandler = new ProxyHandler(target);
TargetInterface proxyTarget = (TargetInterface) Proxy.newProxyInstance(loader, interfaces, proxyHandler);
proxyTarget.targetMethod();
}
}
原始碼分析(原始碼篇幅過多,省略部分由“…”表示)
程式碼中proxyTarget增強類是由Proxy.newProxyInstance(…)生成的,檢視該方法原始碼:
``public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException{
...
// step1:從快取中查詢代理類,若未快取則生成後快取,否則直接從快取中獲取.
Class<?> cl = getProxyClass0(loader, intfs);
try {
...
//step2:反射生成代理類例項
return newInstance(cons, ih);
...
} catch (NoSuchMethodException e) {
...
}
}
程式碼中可以看出,代理類的生成主要分為兩步:
- 生成代理類
- 反射生成代理類例項
step1:
- Proxy.getProxyClass0
private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces) {
...
// Proxy類中維護了一個WeakCache物件,用於快取動態生成的類,WeakCache.get方法不僅執行查詢操作,當物件不存在時也會執行生成操作,下面來看下該方法的原始碼
return proxyClassCache.get(loader, interfaces);
} - WeakCache.get
public V get(K key, P parameter) {
...
while (true) {
if (supplier != null) {
//已從快取中查詢到物件,直接返回
V value = supplier.get();
if (value != null) {
return value;
}
}
if (factory == null) {
//已從快取中查詢到物件,且呼叫該物件的get方法生成代理類後直接返回,get方法實現下文詳述
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
//將新生成的物件快取
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
supplier = factory;
}
} else {
...
}
}
}
}
此方法會不斷的迴圈以及重複判斷,均是在考慮執行緒安全問題。此處未做深究。 - Faotory.get
public synchronized V get() {
...
try {
//實現生成代理類物件,此方法在內部類ProxyClassFactory中實現
value = Objects.requireNonNull(valueFactory.apply(key, parameter));
} finally {
...
}
...
return value;
} ProxyClassFactory.apply
public Class apply(ClassLoader loader, Class[] interfaces) {
//校驗interfaces
...
String proxyPkg = null;
...
//生成packagename,預設為com.sun.proxy
if (proxyPkg == null) {
// if no non-public proxy interfaces, use package
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
//生成classname,採用AutomicLong自增方式
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
// 生成位元組碼檔案
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces);
// 呼叫native方法,載入生成的位元組碼檔案,並返回代理類的引用
try {
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
...
}
}將生成的proxyClassFile位元組碼寫入到檔案並反編譯後,資訊如下:
package com.sun.proxy.$Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import x.constant.proxy.TargetInterface;
public final class 1 extends Proxy implements TargetInterface {
private static Method m3;
private static Method m1;
private static Method m0;
private static Method m2;
public 1(InvocationHandler paramInvocationHandler) throws {
super(paramInvocationHandler);
}
public final void targetMethod() throws {
try {
this.h.invoke(this, m3, null);
return;
}catch (Error|RuntimeException localError) {
throw localError;
}catch (Throwable localThrowable){
throw new UndeclaredThrowableException(localThrowable);
}
}
public final boolean equals(Object paramObject) {
...
}
public final int hashCode() {
...
}
public final String toString() throws {
...
}
static {
try {
m3 = Class.forName("x.constant.proxy.TargetInterface").getMethod("targetMethod", new Class[0]);
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
return;
}catch (NoSuchMethodException localNoSuchMethodException){
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
可以看到,該類位於com.sun.proxy.$Proxy包下,繼承Proxy物件且實現我們自定義的TargetInterface介面;構造方法需要一個InvocationHandler物件做為引數;增強後的targetMethod方法會呼叫InvocationHandler物件的invoke方法。
step2
增強後的類資訊已經載入到JVM中並得到了該類的引用,通過反射機制呼叫該類的構造方法並傳入我們自定義的InvocationHandler物件做為引數,即可生成該代理類物件,此處不再做解析。
通過原始碼的閱讀可以發現,java動態代理的實現過程:
1. 根據Interface動態生成一個該介面的代理類,並通過呼叫InvocationHandler中的invoke方法的方式來實現Interface中定義的方法
2. 動態載入該代理類,並通過反射的方式獲取該代理類的物件。
歸根結底,其實現也是通過位元組碼生成ASM技術來實現的。