jdk動態代理分析
阿新 • • 發佈:2020-12-19
從一下三點分析jdk動態原理分析
1、程式碼示例
2、原始碼分析,
3、執行流程
一、程式碼示例
注意jdk動態代理是基於介面的,cglib是基於類的
//被代理類和代理類都要實現的介面
public interface Subject {
void request() throws Exception;
}
//被代理的類
public class RealSubject implements Subject {
public void request() {
System.out.println("RealSubject execute request()");
}
}
//增強類
public class JdkProxySubject implements InvocationHandler {
private RealSubject realSubject;
public JdkProxySubject(RealSubject realSubject) {
this.realSubject = realSubject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before");
Object result = null;
try {
//利用反射呼叫被代理物件的對應方法
result = method.invoke(realSubject, args);//七
} catch (Exception e) {
throw e;
} finally {
System.out.println("after");
}
return result;
}
}
//測試
public class Client {
public static void main(String[] args) throws Exception {
//通過設定引數,將生成的代理類的.class檔案儲存在本地
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
//通過呼叫Proxy.newProxyInstance生成代理物件
//方法引數為:1)classLoader 2)要代理的介面 3)代理物件的InvocationHandler
//(通過方法引數也可以看出來,JDK代理只能通過代理介面來來實現動態代理)
Subject subject = (Subject) Proxy.newProxyInstance(Client.class.getClassLoader(),
new Class[]{Subject.class}, new JdkProxySubject(new RealSubject()));//一
//呼叫代理物件的request方法。
//(根據InvocationHandler介面的定義,可以知道實際呼叫的是JdkProxySubject裡的invoke方法)
subject.request();//五
}
}
執行結果
before
RealSubject execute request()
after
二、原始碼分析
Proxy.newProxyInstance
去除判斷邏輯後的原始碼
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException {
final Class<?>[] intfs = interfaces.clone();
/*
* Look up or generate the designated proxy class.
*/
//根據提供的介面(在我們的例子中,即Subject介面),生成代理類
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
final Constructor<?> cons = cl.getConstructor(constructorParams);
//呼叫代理類的構造器,構造器引數為InvocationHandler的介面實現類(在我們的例子中,即JdkProxySubject)
return cons.newInstance(new Object[]{h});//三
}
getProxyClass0(loader, intfs);
去除判斷邏輯後的原始碼
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
//已經生成過代理類會放到cache裡,沒有生成過的話,會由ProxyClassFactory建立。
//因此,我們可以直接找到ProxyClassFactory,檢視代理類是如何建立的。
return proxyClassCache.get(loader, interfaces);
}
ProxyClassFactory。apply()
去除判斷邏輯後的原始碼
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// prefix for all proxy class names
private static final String proxyClassNamePrefix = "$Proxy";
// next number to use for generation of unique proxy class names
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
//第一步:確定包名,如果沒有非public的代理介面,包名使用com.sun.proxy
String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
if (proxyPkg == null) {
// if no non-public proxy interfaces, use com.sun.proxy package
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
//第二步:確定類名。(在我們例子中,生成的代理類名為com.sun.proxy.$Proxy0)
/*
* Choose a name for the proxy class to generate.
*/
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
//第三步:根據類名、代理介面等資訊,生成代理類。實際上可以理解為生成.class檔案。
/*
* Generate the specified proxy class.
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
//第四步:根據生成的.class檔案,返回一個代理類Class。此方法為native方法
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
}
}
代理類分析(重點)
public final class $Proxy0 extends Proxy implements Subject {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler h) throws {
super(h);//通過這句,將invocationHandler例項傳給了父類構造器。//四
}
public final boolean equals(Object var1) throws {
try {
return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();//六
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
//$Proxy0繼承了Proxy,且將InvocationHandler h在構造時傳給了Proxy。
//因此,super.h.invoke(this, m3, (Object[])null)其實就是呼叫的invoker handler的invoke方法。
//也正是像InvocationHandler定義中所說的,【當proxy instance的方法被呼叫時,方法呼叫將會委派為invocation handler的invoke方法】。
public final void request() throws Exception {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (Exception | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("proxy.pattern.Subject").getMethod("request", new Class[0]);//二
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
Proxy中InvocationHandler的定義如下
public class Proxy implements java.io.Serializable {
/**
* the invocation handler for this proxy instance.
* @serial
*/
protected InvocationHandler h;
/**
* Constructs a new {@code Proxy} instance from a subclass
* (typically, a dynamic proxy class) with the specified value
* for its invocation handler.
*
* @param h the invocation handler for this proxy instance
*
* @throws NullPointerException if the given invocation handler, {@code h},
* is {@code null}.
*/
protected Proxy(InvocationHandler h) {
Objects.requireNonNull(h);
this.h = h;
}
}
三、執行流程
步驟一、Proxy.newProxyInstance(Client.class.getClassLoader(), new Class[]{Subject.class}, new JdkProxySubject(new RealSubject()));
//建立代理類,傳入單個引數,類載入器,介面集合,增強類集合
步驟二、m3 = Class.forName("proxy.pattern.Subject").getMethod("request", new Class[0]);//通過反射機制得到介面方法
步驟三、cons.newInstance(new Object[]{h});//真正的建立代理物件,並且吧增強器物件
步驟四、super(h);通過代理類的構造方法吧增強物件invovationHandler傳到Proxy物件裡
步驟五、subject.request();呼叫代理物件的介面實現方法
步驟六、super.h.invoke(this, m3, (Object[])null);//獲取增強類呼叫invoke方法
步驟七、method.invoke(realSubject, args);//通過反射傳入被代理物件呼叫對應的方法