1. 程式人生 > >JDK動態代理源碼剖析

JDK動態代理源碼剖析

oca 源碼剖析 tar 磁盤文件 prefix weak get tcl sub

關鍵代碼:

1.Proxy.newInstance:

private static final Class<?>[] constructorParams = { InvocationHandler.class };
Class<?> cl = getProxyClass0(loader, intfs);
final Constructor<?> cons = cl.getConstructor(constructorParams);
return cons.newInstance(new Object[]{h});

2.Proxy.getProxyClass0:

// otherwise, it will create the proxy class via the ProxyClassFactory
return proxyClassCache.get(loader, interfaces);

3.WeakCache.get(由2註釋可知,首次是由ProxyClassFactory生成的class對象,proxyClassCache即WeakCache):

Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));

可見,這裏調用ProxyClassFactory的apply方法;

4.ProxyClassFactory.apply:

long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
return defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);

這裏先取一個原子整數作為序號,生成代理對象名稱,com.sun.proxy.$Proxy0.class,
然後通過ProxyGenerator.generateProxyClass獲得class的字節碼,然後調用native方法defineClass0創建class對象。

由上可知,先在ProxyClassFactory的apply方法中通過ProxyGenerator.generateProxyClass得到字節碼,調用defineClass0由字節碼得到class對象(是個native方法),然後在Proxy.newInstance裏得到這個class對象的構造器,然後反射得到代理對象實例。
通過ProxyGenerator.generateProxyClass(Openjdk能看到該類的源碼)可以生成代理對象的字節碼,然後將其寫到磁盤文件(.class後綴),即可看到代理對象的class文件了,使用jd反編譯:

該class繼承了Proxy,實現了被代理對象的接口。構造方法傳入InvocationHandler,調用super(invocationHandler);實現的被代理接口的方法裏面其實是調用的invocationHandler.invoke方法(Object proxy參數傳入的代理對象this)。

使用動態代理:

1)實現InvocationHandler接口(增強),並持有被代理對象實例,並在它的invoke方法裏面寫增強邏輯,該方法的參數是代理對象,方法和參數,在invoke合適的位置調用被代理對象的方法(使用反射的方式method.invoke(target, args));
2)使用Proxy.newInstance創建代理對象,classloader使用被代理對象的classloader即可(target.getClass.getClassLoader),interfaces使用被代理對象的接口數組(target.getClass.getInterfaces)。

JDK動態代理源碼剖析