jdk动态代理实现原理

写在前面:

  • 大神和diao炸天的亲请绕道..
  • 关于代理模式的概念这里省去,大家可以放鸟尽情搜..
  • 关于为什么叫动态代理,个人理解是代理的类是在运行时动态生成的,大家也可以参考网上的理解..
  • 文笔很差,所以文字较少,都在代码和注释中..

=======一点不华丽的分割线————————-

开门见山,lets go..

java中可以通过jdk提供的 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
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
throws IllegalArgumentException {

//InvocationHandler不能为空,因为对代理对象的所有方法调用实际上都会委托到InvocationHandler的invoke方法,
//这个我们后面通过查看产生的代理类的源代码便会一目了然
if (h == null) {
throw new NullPointerException();
}

//这个是核心的地方,通过提供的ClassLoader和interface列表来产生代理类,具体的实现可以参考getProxyClass这个方法的实现,
//真正的工作是由sun.misc.ProxyGenerator这个类来完成的,可以google查看具体的逻辑.在我们的程序中通过设置
//System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true")可以查看产生的类文件
Class cl = getProxyClass(loader, interfaces);

//因为代理类继承了Proxy类.而Proxy中定义了构造函数protected Proxy(InvocationHandler h),所以可以反射得到Constructer实例
//创建代理对象
try {
Constructor cons = cl.getConstructor(constructorParams);
return (Object) cons.newInstance(new Object[] { h });
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString());
} catch (IllegalAccessException e) {
throw new InternalError(e.toString());
} catch (InstantiationException e) {
throw new InternalError(e.toString());
} catch (InvocationTargetException e) {
throw new InternalError(e.toString());
}
}

下面通过个例子来说明下:
先来定义一个接口,jdk的动态代理基于接口来创建代理类,不能基于类的原因是java不支持多重继承,而代理类都会继承Proxy类(个人理解).

1
2
3
4
5
6
7
8
9
10
11
/**
* Subject
*
* @author Kevin Fan
* @since 2013-9-13 下午2:43:33
*/

public interface Subject {
void pub(String key, String content);

String sub(String key);
}

再来一个具体的实现,在代理模式中可以叫它的实例可以叫target,这个是真正执行操作的对象

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
/**
* SimpleSubject
*
* @author Kevin Fan
* @since 2013-9-13 下午2:45:03
*/

public class SimpleSubject implements Subject {
private Map<String, String> msg = new ConcurrentHashMap<String, String>();

public void pub(String key, String content) {
System.out.println("pub msg: key is " + key + ", content is " + content);
msg.put(key, content);
}

public String sub(String key) {
if (msg.containsKey(key)) {
String ret = msg.get(key);
System.out.println("sub msg: key is " + key + ", result is " + ret);
return ret;
}

return null;
}

}

好,接下来我们来写个动态代理工厂,根据 不同的target来创建动态代理对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* SubjectProxyFactory
*
* @author Kevin Fan
* @since 2013-9-13 下午2:47:24
*/

public class SubjectProxyFactory {
//TODO: cache
public static Subject getSubject(final Subject realSubject) {
return (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), new Class[] { Subject.class },
new InvocationHandler() {

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("\naction before method invocation....");
Object retVal = method.invoke(realSubject, args);
System.out.println("action after method invocation....\n");
return retVal;
}
});
}
}

可以看到这是一个简单的实现,只是在真实对象执行前后各打一句信息..

接下来用一个 main函数来把这些结合起来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* Demo
*
* @author Kevin Fan
* @since 2013-9-13 下午2:50:28
*/

public class Demo {
public static void main(String[] args) {
//设置此系统属性,以查看代理类文件
System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

//创建真实对象
Subject subj = new SimpleSubject();
subj.pub("name", "kevin.fan");
subj.sub("name");

//创建代理对象
Subject proxy = SubjectProxyFactory.getSubject(subj);
proxy.pub("hobby", "r&b music");
proxy.sub("name");
}
}

ok,小手抖一下,走你,看下执行结果

1
2
3
4
5
6
7
8
9
10
11
12
pub msg: key is name, content is kevin.fan
sub msg: key is name, result is kevin.fan


action before method invocation....
pub msg: key is hobby, content is r&b music
action after method invocation....


action before method invocation....
sub msg: key is name, result is kevin.fan
action after method invocation....

可以看到在调用代理对象的方法时,添加的额外动作已经生效,接下来我们看下生成的代理类的代码..

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import com.aliyun.demo.kevin.coder.lang.proxy.Subject;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

//这里很清楚了,代理类继承了Proxy类,并且实现了Proxy.newProxyInstance这个方法中传入的接口

public final class $Proxy0 extends Proxy
implements Subject
{


//这些方法在下面的static init block中进行初始化
private static Method m4;
private static Method m1;
private static Method m3;
private static Method m0;
private static Method m2;

static
{
try
{
m4 = Class.forName("com.aliyun.demo.kevin.coder.lang.proxy.Subject").getMethod("sub", new Class[] { Class.forName("java.lang.String") });
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m3 = Class.forName("com.aliyun.demo.kevin.coder.lang.proxy.Subject").getMethod("pub", new Class[] { Class.forName("java.lang.String"), Class.forName("java.lang.String") });
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());
}
}

//构造函数,接收一个 InvocationHandler作为参数,这就是为什么Proxy.newProxyInstance方法里可以
//通过InvocationHandler实例作为参数来反射获取Constructer实例
public $Proxy0 paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}

//下面通过这个来看下代理对象中方法是怎样调用的
public final String sub(String paramString)
throws
{

try
{
//全部是通过调用InvocationHandler的invoke方法,传入对应的方法和参数
return (String)this.h.invoke(this, m4, new Object[] { paramString });
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}

public final boolean equals(Object paramObject)
throws
{

try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}

public final void pub(String paramString1, String paramString2)
throws
{

try
{
this.h.invoke(this, m3, new Object[] { paramString1, paramString2 });
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}

public final int hashCode()
throws
{

try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}

public final String toString()
throws
{

try
{
return (String)this.h.invoke(this, m2, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}

}