jvm_字节码看动态代理

1. jdk 动态代理基本使用

1
2
3
public interface Subscribe {
void subscrib();
}
1
2
3
4
5
6
	public class SubImpl implements Subscribe {
@Override
public void subscrib() {
System.out.println("subscribe invoked ");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
	public class SubHandler implements InvocationHandler {

private Object realObj;

public SubHandler(Object realObj) {
this.realObj = realObj;
}

@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {


if (method.getDeclaringClass() == Object.class) {
return method.invoke(o,objects);
}

System.out.println("before invoked ");


Object invoke = method.invoke(realObj, objects);

System.out.println("after invoked ");

return invoke;
}
}
测试代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
	public class MyClass {


public static void main(String[] args) {

System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles","true");


Subscribe subscribe = new SubImpl();

Subscribe proxy = (Subscribe) Proxy.newProxyInstance(subscribe.getClass().getClassLoader(),
subscribe.getClass().getInterfaces(), new SubHandler(subscribe));

proxy.subscrib();
}

}
以上代码是对于jdk动态代理的基本使用。值得注意的是,jdk的动态代理类, 必须是有接口的。
执行结果如下: 
    before invoked 
    subscribe invoked 
    after invoked 

2. 源码分析

1
2
Subscribe proxy = (Subscribe) Proxy.newProxyInstance(subscribe.getClass().getClassLoader(),
subscribe.getClass().getInterfaces(), new SubHandler(subscribe));
通过对于proxy类进行打印发现,他的父类其实是 java.lang.reflect.Proxy
下面我们具体分析,我们的 proxy对象是怎么生成的

1. 首先进入Proxy.newProxyInstance静态方法.鉴于代码篇幅较长,做了一部分删减。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
......

/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);

final Constructor<?> cons = cl.getConstructor(constructorParams);
.......

return cons.newInstance(new Object[]{h});

}


通过以上代码,我们发现关键点 在这里主要做了三件事
1. 通过 getProxyClass0 方法获取 Class对象
2. 调用默认构造方法 conns
3. 通过构造方法生成我们需要的返回对象 

这里我们再次进入getProxyClass0 看如何生成 class对象的。
跟进代码进入到 ProxyClassFactory.apply 方法
1
2
3
4
5
6
7
8
9
10
11

byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);

try {
return defineClass0(loader, proxyName,
proxyClassFile, 0,proxyClassFile.length);
} catch (ClassFormatError e) {

}

首先通过 ProxyGenerator.generateProxyClass生成字节码的数组,然后通过
defineClass0 生成class对象。 defineClass0是native方法。
到目前为止,我们就完成了整个流程的分析。

3. 我们通过Proxy.newProxyInstance类内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
	public final class $Proxy0 extends Proxy implements Subscribe {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;

public $Proxy0(InvocationHandler var1) throws {
super(var1);
}

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 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 void subscrib() throws {
try {
super.h.invoke(this, m3, (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"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.example.lib.Subscribe").getMethod("subscrib");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
以上是我们通过动态代理生成的类,继承了 Proxy,实现我们的Subscribe接口
默认实现了object中的 equals,toString,hashCode方法
以及Subscribe接口中的方法
以上方法提的人内容大同小异,通过静态代码块实例化的method,最后调用我们的
handler的invoke方法