之前和同學聊起代理模式,順嘴提到了動態代理,就順便看了一下源碼,話不多說,開始分析,和之前一樣爲了方便理解,我會直接在代碼中註釋
這是一段很常見的動態代理代碼,TestInterface是一個接口,裏面只有一個test方法,TestInterfaceImpl類實現了TestInterface接口,代碼也比較簡單,我就不全部貼出來了
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Test implements InvocationHandler {
public TestInterface ti;
public Object newProxyInstance(TestInterface ti) {
this.ti = ti;
//重點
return Proxy.newProxyInstance(ti.getClass().getClassLoader(), ti.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("執行方法前的操作");
if(method.getName().equals("test"))
{
ti.test();
}
System.out.println("執行方法後的操作");
return null;
}
public static void main(String[] args) {
Test test =new Test ();
TestInterface ti = (TestInterface)test.newProxyInstance(new TestInterfaceImpl());
ti.test();
}
}
重點是Proxy.newProxyInstance方法
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h) {
//若傳入的動態代理類爲空拋出異常
Objects.requireNonNull(h);
//獲取當前系統的安全檢查器
//因爲這裏會進行類加載和io操作,需要進行安全檢查
final Class<?> caller = System.getSecurityManager() == null
? null
: Reflection.getCallerClass();
/*
* Look up or generate the designated proxy class and its constructor.
*/
//關鍵方法
Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);
//此處只是調用Constructor的newInstance方法
//把動態代理對象傳入,調用對應的構造方法
//返回一個動態代理後的實體類
//意義不大,這裏就不多介紹
return newProxyInstance(caller, cons, h);
}
進入關鍵方法getProxyConstructor
private static Constructor<?> getProxyConstructor(Class<?> caller,
ClassLoader loader,
Class<?>... interfaces)
{
//判斷需要代理的接口是否爲多個,進行簡單轉換
//if else內容幾乎一致,就只對前面的if內容進行分析,不再贅述
if (interfaces.length == 1) {
Class<?> intf = interfaces[0];
//判斷是否需要進行安全檢查
if (caller != null) {
checkProxyAccess(caller, loader, intf);
}
//重點方法,我會進行單獨講解
return proxyCache.sub(intf).computeIfAbsent(
loader,
(ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
);
} else {
// interfaces cloned
final Class<?>[] intfsArray = interfaces.clone();
if (caller != null) {
checkProxyAccess(caller, loader, intfsArray);
}
final List<Class<?>> intfs = Arrays.asList(intfsArray);
return proxyCache.sub(intfs).computeIfAbsent(
loader,
(ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
);
}
}
這段代碼相當優雅,把lanbda表達式寫的出神入化(但是我不建議大家平時這樣寫,可讀性極差,我自己看這段代碼蒙了有一會)
return proxyCache.sub(intf).computeIfAbsent(
loader,
(ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
);
首先我們來看computeIfAbsent方法
public V computeIfAbsent(ClassLoader cl,
BiFunction<
? super ClassLoader,
? super CLV,
? extends V
> mappingFunction)
lanbda表達式推導的就是BiFunction接口的方法,進入BiFunction接口
public interface BiFunction<T, U, R> {
R apply(T t, U u);
。。。省略。。。
}
問題來了,我們可以把lanbda表達式寫成下面的代碼
R apply(T ld, U clv){
return new ProxyBuilder(ld, clv.key()).build();
}
然後通過類型推導(根據computeIfAbsent方法進行推導)將代碼推導爲
R apply(ClassLoader ld, U clv){
return new ProxyBuilder(ld, clv.key()).build();
}
再根據sub方法,和AbstractClassLoaderValue,Sub類進行進一步的推導
public abstract class AbstractClassLoaderValue<CLV extends AbstractClassLoaderValue<CLV, V>, V>
public final class Sub<K> extends AbstractClassLoaderValue<Sub<K>, V>
public <K> Sub<K> sub(K key) {
return new Sub<K>(key);
}
最終才能得到推導後的方法
R apply(ClassLoader ld, Sub clv){
return new ProxyBuilder(ld, clv.key()).build();
}
但是,此時返回值依然是不確定的,根據build的返回值推導,爲Constructor,最終的方法才能得到
Constructor apply(ClassLoader ld, Sub clv){
return new ProxyBuilder(ld, clv.key()).build();
}
確實挺優雅的,就是太難理解,進入computeIfAbsent方法進行分析,設計的有點繞,猜測是爲了解決複用性
public V computeIfAbsent(ClassLoader cl,
BiFunction<
? super ClassLoader,
? super CLV,
? extends V
> mappingFunction) throws IllegalStateException {
//創建map集合,注意,此處會根據類加載器加載對應的map集合
ConcurrentHashMap<CLV, Object> map = map(cl);
@SuppressWarnings("unchecked")
//獲取自身對象此處爲sub對象
CLV clv = (CLV) this;
Memoizer<CLV, V> mv = null;
while (true) {
//查看mv對象是否爲空,如果爲空(即,首次進入循環),嘗試從集合中獲取vsl
//如果可以獲取,認爲該類已經加載,直接返回類對象
//否則進行添加並賦值給val
Object val = (mv == null) ? map.get(clv) : map.putIfAbsent(clv, mv);
//當第一次運行時,val和mv均爲null
if (val == null) {
if (mv == null) {
// create Memoizer lazily when 1st needed and restart loop
//創建Memoizer對象
//只做一件事,將三個參數賦值給自身的成員變量
mv = new Memoizer<>(cl, clv, mappingFunction);
continue;
}
// mv != null, therefore sv == null was a result of successful
// putIfAbsent
try {
// trigger Memoizer to compute the value
//主要方法
V v = mv.get();
// attempt to replace our Memoizer with the value
//替換元素
map.replace(clv, mv, v);
// return computed value
return v;
} catch (Throwable t) {
// our Memoizer has thrown, attempt to remove it
map.remove(clv, mv);
// propagate exception because it's from our Memoizer
throw t;
}
} else {
try {
//如果進行到這一步,說明map集合中存在已經加載好的類
//判斷是否爲Memoizer(若爲Memoizer可能是多線程條件下get方法尚未完成)
//然後返回對應的類,或是繼續調用get方法
return extractValue(val);
} catch (Memoizer.RecursiveInvocationException e) {
// propagate recursive attempts to calculate the same
// value as being calculated at the moment
throw e;
} catch (Throwable t) {
// don't propagate exceptions thrown from foreign Memoizer -
// pretend that there was no entry and retry
// (foreign computeIfAbsent invocation will try to remove it anyway)
}
}
// TODO:
// Thread.onSpinLoop(); // when available
}
}
get方法
public V get() throws RecursiveInvocationException {
V v = this.v;
if (v != null) return v;
Throwable t = this.t;
if (t == null) {
synchronized (this) {
if ((v = this.v) == null && (t = this.t) == null) {
if (inCall) {
throw new RecursiveInvocationException();
}
inCall = true;
try {
this.v = v = Objects.requireNonNull(
//前面後面都是健壯性和複用性檢測
//沒什麼好看的關鍵是是這裏
//調用前面用lanbda表達式傳入發方法
mappingFunction.apply(cl, clv));
} catch (Throwable x) {
this.t = t = x;
} finally {
inCall = false;
}
}
}
}
if (v != null) return v;
if (t instanceof Error) {
throw (Error) t;
} else if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new UndeclaredThrowableException(t);
}
}
回到之前的build方法
Constructor<?> build() {
//核心,返回class對象
Class<?> proxyClass = defineProxyClass(module, interfaces);
final Constructor<?> cons;
try {
//返回對應的構造方法,沒什麼好看的
cons = proxyClass.getConstructor(constructorParams);
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
return cons;
}
defineProxyClass方法
private static Class<?> defineProxyClass(Module m, List<Class<?>> interfaces) {
String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
/*
* Record the package of a non-public proxy interface so that the
* proxy class will be defined in the same package. Verify that
* all non-public proxy interfaces are in the same package.
*/
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL; // non-public, final
String pkg = intf.getPackageName();
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) {
// all proxy interfaces are public
proxyPkg = m.isNamed() ? PROXY_PACKAGE_PREFIX + "." + m.getName()
: PROXY_PACKAGE_PREFIX;
} else if (proxyPkg.isEmpty() && m.isNamed()) {
throw new IllegalArgumentException(
"Unnamed package cannot be added to " + m);
}
if (m.isNamed()) {
if (!m.getDescriptor().packages().contains(proxyPkg)) {
throw new InternalError(proxyPkg + " not exist in " + m.getName());
}
}
/*
* Choose a name for the proxy class to generate.
*/
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg.isEmpty()
? proxyClassNamePrefix + num
: proxyPkg + "." + proxyClassNamePrefix + num;
ClassLoader loader = getLoader(m);
trace(proxyName, m, loader, interfaces);
/*
* Generate the specified proxy class.
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces.toArray(EMPTY_CLASS_ARRAY), accessFlags);
try {
Class<?> pc = UNSAFE.defineClass(proxyName, proxyClassFile,
0, proxyClassFile.length,
loader, null);
reverseProxyCache.sub(pc).putIfAbsent(loader, Boolean.TRUE);
return pc;
} catch (ClassFormatError e) {
/*
* A ClassFormatError here means that (barring bugs in the
* proxy class generation code) there was some other
* invalid aspect of the arguments supplied to the proxy
* class creation (such as virtual machine limitations
* exceeded).
*/
throw new IllegalArgumentException(e.toString());
}
}
其他都是做一些檢驗,沒什麼好說的,其實這麼一大段重要的就下面
//生成動態代理字節碼
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces.toArray(EMPTY_CLASS_ARRAY), accessFlags);
try {
//通過類加載器加載字節碼
Class<?> pc = UNSAFE.defineClass(proxyName, proxyClassFile,
0, proxyClassFile.length,
loader, null);
reverseProxyCache.sub(pc).putIfAbsent(loader, Boolean.TRUE);
return pc;
最終生成字節碼也就是在內存中生成.class文件的方法,大家看看就行了,太多了,而且也沒啥技術含量,方法和需要實現的接口方法內部字節碼都是基本固定的,無非是把實現的接口方法轉發到一個統一的方法中,再通過統一方法調用我們自己實現的invoke方法,就是實現的接口,導包的路徑,類名稱不同,稍有jvm常識就能自己寫一個,就是費時間而已
private byte[] generateClassFile() {
/* ============================================================
* Step 1: Assemble ProxyMethod objects for all methods to
* generate proxy dispatching code for.
*/
/*
* Record that proxy methods are needed for the hashCode, equals,
* and toString methods of java.lang.Object. This is done before
* the methods from the proxy interfaces so that the methods from
* java.lang.Object take precedence over duplicate methods in the
* proxy interfaces.
*/
//添加hashCode,equals,toString方法
addProxyMethod(hashCodeMethod, Object.class);
addProxyMethod(equalsMethod, Object.class);
addProxyMethod(toStringMethod, Object.class);
/*
* Now record all of the methods from the proxy interfaces, giving
* earlier interfaces precedence over later ones with duplicate
* methods.
*/
for (Class<?> intf : interfaces) {
for (Method m : intf.getMethods()) {
addProxyMethod(m, intf);
}
}
/*
* For each set of proxy methods with the same signature,
* verify that the methods' return types are compatible.
*/
for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
checkReturnTypes(sigmethods);
}
/* ============================================================
* Step 2: Assemble FieldInfo and MethodInfo structs for all of
* fields and methods in the class we are generating.
*/
try {
methods.add(generateConstructor());
//開始生成代理方法
for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
for (ProxyMethod pm : sigmethods) {
// add static field for method's Method object
//生成對應的方法訪問標誌
fields.add(new FieldInfo(pm.methodFieldName,
"Ljava/lang/reflect/Method;",
ACC_PRIVATE | ACC_STATIC));
// generate code for proxy method and add it
//生成代理方法
methods.add(pm.generateMethod());
}
}
//添加靜態塊
methods.add(generateStaticInitializer());
} catch (IOException e) {
throw new InternalError("unexpected I/O Exception", e);
}
if (methods.size() > 65535) {
throw new IllegalArgumentException("method limit exceeded");
}
if (fields.size() > 65535) {
throw new IllegalArgumentException("field limit exceeded");
}
/* ============================================================
* Step 3: Write the final class file.
*/
/*
* Make sure that constant pool indexes are reserved for the
* following items before starting to write the final class file.
*/
//獲取類名(稍後還要進行拼接)和父類名
cp.getClass(dotToSlash(className));
cp.getClass(superclassName);
//獲取所有接口名
for (Class<?> intf: interfaces) {
cp.getClass(dotToSlash(intf.getName()));
}
/*
* Disallow new constant pool additions beyond this point, since
* we are about to write the final constant pool table.
*/
cp.setReadOnly();
ByteArrayOutputStream bout = new ByteArrayOutputStream();
DataOutputStream dout = new DataOutputStream(bout);
try {
/*
* Write all the items of the "ClassFile" structure.
* See JVMS section 4.1.
*/
// u4 magic;
//添加魔數
dout.writeInt(0xCAFEBABE);
// u2 minor_version;
//添加版本信息
dout.writeShort(CLASSFILE_MINOR_VERSION);
// u2 major_version;
//添加小版本信息
dout.writeShort(CLASSFILE_MAJOR_VERSION);
//添加常量池
cp.write(dout); // (write constant pool)
// u2 access_flags;
//添加標誌位
dout.writeShort(accessFlags);
// u2 this_class;
//添加類名
dout.writeShort(cp.getClass(dotToSlash(className)));
// u2 super_class;
//添加父類名
dout.writeShort(cp.getClass(superclassName));
// u2 interfaces_count;
//添加接口表標誌位
dout.writeShort(interfaces.length);
// u2 interfaces[interfaces_count];
//添加接口
for (Class<?> intf : interfaces) {
dout.writeShort(cp.getClass(
dotToSlash(intf.getName())));
}
// u2 fields_count;
//添加字段表標誌位
dout.writeShort(fields.size());
// field_info fields[fields_count];
//添加字段
for (FieldInfo f : fields) {
f.write(dout);
}
// u2 methods_count;
//添加方法表標誌位
dout.writeShort(methods.size());
// method_info methods[methods_count];
//添加方法
for (MethodInfo m : methods) {
m.write(dout);
}
// u2 attributes_count;
//類文件屬性,稍後會在另外一個方法設置
dout.writeShort(0); // (no ClassFile attributes for proxy classes)
} catch (IOException e) {
throw new InternalError("unexpected I/O Exception", e);
}
return bout.toByteArray();
}
通過反射獲取生成的class字節碼
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;
public class Test {
private static void saveProxyFile() {
FileOutputStream out = null;
try {
Class clazz = Class.forName("java.lang.reflect.ProxyGenerator");
Method m = clazz.getDeclaredMethod("generateProxyClass", String.class, Class[].class);
m.setAccessible(true);
byte[] bs = (byte[]) m.invoke(null, "$Proxy0", new Class[]{TestInterface.class});
out = new FileOutputStream("$Proxy0.class");
out.write(bs);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.flush();
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
saveProxyFile();
}
}
生成的class字節碼
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements TestInterface {
//方法對象
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
//使用父類的構造方法處理
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
//將所有方法轉發到父類h屬性的invoke方法
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void test() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
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);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (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"));
m3 = Class.forName("TestInterface").getMethod("test");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
父類的構造方法,最終所有方法都指向我們傳入的類的invoke方法
protected Proxy(InvocationHandler h) {
Objects.requireNonNull(h);
this.h = h;
}
獲取class對象的方法,因爲是native 修飾,我就不繼續下去了
public native Class<?> defineClass0(String name, byte[] b, int off, int len,
ClassLoader loader,
ProtectionDomain protectionDomain);
至此,分析結束