JAVA代理之JDK动态代理

动态代理:在程序运行时,通过反射机制动态创建而成。

用到的两个类, java.lang.reflect.InvocationHandler java.lang.reflect.Proxy

示例

UserService.java

1
2
3
4
5
6
7
8
9
10
package cn.cecurio.proxy.dynamic.jdk;
/**
* @author: Cecurio
* @create: 2018-02-25 16:20
**/
public interface UserService {
void add();
void update();
}

UserServiceImpl.java 委托类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package cn.cecurio.proxy.dynamic.jdk;
/**
* @author: Cecurio
* @create: 2018-02-25 16:22
**/
public class UserServiceImpl implements UserService {
public void add() {
System.out.println("UserServiceImpl.add()");
}
public void update() {
System.out.println("UserServiceImpl.update()");
}
}

ServiceInvocationHandler.java

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
package cn.cecurio.proxy.dynamic.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author: Cecurio
* @create: 2018-02-25 16:24
**/
public class ServiceInvocationHandler implements InvocationHandler {
private Object target;
public ServiceInvocationHandler(Object target) {
this.target = target;
}
/**
* 创建代理实例
*
* @return
* @throws Throwable
*/
public Object getProxy() throws Throwable {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
target.getClass().getInterfaces(),
this);
}
/**
* 实现 InvocationHandler 接口, 必须实现invoke方法
* 执行目标对象的方法, 并进行增强
*
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
System.out.println("代理方法开始");
System.out.println("被代理的方法是:" + method);
// 执行目标对象的方法
result = method.invoke(target, args);
System.out.println("代理方法结束");
return result;
}
}

JdkProxyTest.java 测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package cn.cecurio.proxy.dynamic.jdk;
/**
* @author: Cecurio
* @create: 2018-02-25 16:42
**/
public class JdkProxyTest {
public static void main(String[] args) throws Throwable {
UserService userService = new UserServiceImpl();
ServiceInvocationHandler handler = new ServiceInvocationHandler(userService);
UserService userServiceProxy = (UserService) handler.getProxy();
userServiceProxy.add();
}
}

执行结果

1
2
3
4
代理方法开始
被代理的方法是:public abstract void cn.cecurio.proxy.dynamic.jdk.UserService.add()
UserServiceImpl.add()
代理方法结束

JDK动态代理的用法:

  1. 一个接口
  2. 一个接口的实现类, 用作委托类
  3. 一个实现 java.lang.reflect.InvocationHandler 的类, 这个类有个成员变量(上面的接口实现类), 此类必须实现invoke(Object proxy, Method method, Object[] args)方法
  4. 必须要有创建代理类的操作, 是上述代码的UserService userServiceProxy = (UserService) handler.getProxy();的部分, 生成的代理类继承Proxy, 实现委托类实现的接口

代理类的字节码是从哪里生成的?

进入java.lang.reflect.Proxy.ProxyClassFactory#apply()方法,最终是通过调用sun.misc.ProxyGenerator#generateProxyClass(final String proxyName, Class<?>[] interfaces, int accessFlags)方法生成byte[],然后调用方法java.lang.reflect.Proxy#defineClass0,由类加载器加载生成对应的Class对象

到底生成了怎样的字节码? 我们可以自己调用sun.misc.ProxyGenerator#generateProxyClass(final String proxyName, Class<?>[] interfaces, int accessFlags) 这个方法去生成代理类的字节码,然后反编译看看

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
package cn.cecurio.proxy;
import sun.misc.ProxyGenerator;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
interface Service {
void add(String username,String password);
void update(String username,String password);
}
/**
* @author: Cecurio
* @create: 2018-04-07 2:11
**/
public class ProxyGeneratorTest {
public static void main(String[] args) {
String name = "ProxyService";
byte[] data = ProxyGenerator.generateProxyClass(name, new Class[]{Service.class});
FileOutputStream out = null;
try {
out = new FileOutputStream(name + ".class");
out.write(data);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != out) try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

动态生成的Service的实现类反编译后内容如下

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
import cn.cecurio.proxy.Service;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class ProxyService
extends Proxy
implements Service
{
private static Method m1;
private static Method m3;
private static Method m4;
private static Method m2;
private static Method m0;
public ProxyService(InvocationHandler paramInvocationHandler)
{
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject)
{
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 add(String paramString1, String paramString2)
{
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 void update(String paramString1, String paramString2)
{
try
{
this.h.invoke(this, m4, new Object[] { paramString1, paramString2 });
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString()
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode()
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m3 = Class.forName("cn.cecurio.proxy.Service").getMethod("add", new Class[] { Class.forName("java.lang.String"), Class.forName("java.lang.String") });
m4 = Class.forName("cn.cecurio.proxy.Service").getMethod("update", new Class[] { Class.forName("java.lang.String"), Class.forName("java.lang.String") });
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}

看到生成的构造函数需要一个InvocationHandler的实例,这个实例是怎么传递给ProxyService的构造函数的呢?是通过java.lang.reflect.Proxy#newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)这个方法,具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
// cl是代理生成的Class对象
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
// 通过反射生成代理类的实例
return cons.newInstance(new Object[]{h});

Service接口的每个方法实现里都有类似下面的代码

1
this.h.invoke(this, m4, new Object[] { paramString1, paramString2 });

总结

JDK动态代理只做了两件事:

  1. Look up or generate the designated proxy class.(查找或生成指定的代理类)
  2. Invoke its constructor with the designated invocation handler.(使用指定的调用处理程序调用它的构造函数)

参考文章

http://blog.csdn.net/jiankunking/article/details/52143504

If you think the content is useful to you.