JDK动态代理实现原理分析

JDK动态代理

JDK动态代理允许在运行时通过反射创建Java接口的实现。代理可以被看作是一个将方法调用转发给目标实例并最终将目标实例产生的任何结果返回给调用方的主体。由于调用链将通过代理,代理本身也将能够在目标方法调用前后执行任意处理。非常流行的Spring框架使用JDK动态代理作为其代理创建策略之一。当我们在Spring服务中声明一个事务方法时,容器将创建一个代理,该代理将拦截对目标方法的调用,并用所需的事务管理指令来修饰它。

JDK动态代理是JDK附带的一个特性,由java.lang.reflect.* 包提供支持。它必须使用接口来提供代理对象。在JDK动态代理逻辑中,必须实现java.lang.reflect.InvocationHandler接口才能实现代理逻辑类。实现JDK动态代理需要几下几步:

  • 创建接口
  • 创建一个接口实现类的实例对象,这个实例对象就是目标对象
  • 创建一个代理类,这个类必须实现java.lang.reflect.InvocationHandler接口

JDK动态代理相关类介绍

在Java的动态代理机制中,有两个重要的类和接口,一个是InvocationHandler(Interface),另一个是proxy(Class),这个类和接口必须用来实现动态代理。

InvocationHandler

每个动态代理类必须实现java.lang.reflect.InvocationHandler,每个代理类得是实例都与一个handler关联,当我们通过一个代理对象调用一个方法,对这个方法的调用被转发给InvocationHandler接口的invoke方法调用,然后在这个接口中通过反射调用这个方法。

1
2
3
4
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}

这个接口有三个参数:

  • Proxy:指JDK动态生成的final修饰的代理对象
  • Method:指的是我们要调用目标对象的方法的方法对象
  • Args:指调用目标对象的方法的方法参数

Proxy

代理类的作用是动态创建代理对象类,最常用的方法是newProxyInstance

1
2
3
4
5
6
7
8
9
public class Proxy implements java.io.Serializable {
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException {
...
}
}

newProxyInstance方法的三个参数分别如下:

  • Loader:一个类加载器对象,它定义了要为加载生成代理对象的类加载器。
  • Interfaces:一个接口对象数组,这意味着我们将为需要代理的对象提供一组接口,生成的代理对象实现这些接口。
  • InvocationHandler :一个InvocationHandler对象,它表示在动态代理对象调用方法时与哪个InvocationHandler对象关联。可以把它理解为一个拦截器,拦截方法的调用,在目标方法调用前后进行通知。

用JDK代理创建代理

动态代理类是一个类,它是在运行时生成的类。生成它时,必须向它提供一组接口。然后类公布这些接口的实现。你可以将类实例用作这些接口中的任何一个。当然,这个类是一个代理。它不会做实质性的工作。在生成他的实例时,必须提供一个handler来接管实际工作。

假设你要检查是否有权限调用目标对象的某个方法,如果授权失败,可以抛出一个运行时异常AuthorizationException(本例中只是简单打印信息)。接口授权具体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.wonglay;

import java.lang.reflect.Method;

/**
* @author wonglay
* @description 简单的授权服务
*/
public interface AuthorizationService {

void authorize(Method method);
}

假设有一个PersistenceServiceImpl类实现了PersistenceService接口,它有两个方法:save和load。现在需要检查是否有权限调用这两个方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.wonglay;

/**
* @author wonglay
* @description PersistenceService接口简单实现
*/
public class PersistenceServiceImpl implements PersistenceService {

@Override
public void save(Long id, String data) {
System.out.println(data + " has been saved successfully");
}

@Override
public String load(Long id) {
return "wonglay.com";
}
}

现在授权接口和需要授权的接口都有了,现在需要将这两个类关联起来,我们需要实现一个InvocationHandler接口:

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
package com.wonglay;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
* @author wonglay
* @description
*/
public class PersistenceServiceInvocationHandler implements InvocationHandler {

/**
* 用于权限检查
*/
private final AuthorizationService authorizationService;

/**
* 目标对象
*/
private final Object target;

public PersistenceServiceInvocationHandler(AuthorizationService authorizationService, Object target) {
this.authorizationService = authorizationService;
this.target = target;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// do前置通知
authorizationService.authorize(method);
Object result = method.invoke(target, args);
// do其他后置通知。。。。
return result;
}
// 创建代理对象
public Object getProxy() {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this);
}
}

生成的代理类会继承一个java.lang.reflect.Proxy类,java.lang.reflect.Proxy类声明了一个InvocationHandler变量,调用代理对象的方法时会委托给InvocationHandler(本例中就是PersistenceServiceInvocationHandler)的invoke,在invoke方法中通过反射调用目标方法,因此可以对方法进行增强。这几个类之间的关系如图3.1。

图3.1

面是为PersistenceServicel类创建代理对象的过程:

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
package com.wonglay;

/**
* @author wonglay
* @description
*/
public class Main {

public static void main(String[] args) {

PersistenceService persistenceService = new PersistenceServiceImpl();
// 权限检查的简单实现
AuthorizationService authorizationService = (method) -> {
String methodName = method.getName();
System.out.println("[" + methodName + "] method authenticating...");
};
// 设置权限检查服务和目标对象
PersistenceServiceInvocationHandler persistenceServiceInvocationHandler =
new PersistenceServiceInvocationHandler(authorizationService, persistenceService);
// 创建代理对象
PersistenceService proxy = (PersistenceService) persistenceServiceInvocationHandler.getProxy();

System.out.println(proxy.load(1L));

}

}

打印结果如图3.2

图3.2

实现原理探究

上面只是简单介绍了一下创建代理的过程,接下来将分析具体JDK是如何生成代理类,以及生成的代理类是什么样子,我们可以加上一个JVM参数,将生成的代理类写到磁盘。

1
2
3
4
5
6
7
8
public class Main {

public static void main(String[] args) {
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
PersistenceService persistenceService = new PersistenceServiceImpl();
// 权限检查的简单实现
.....
}

生成的代理类如下:

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

package com.sun.proxy;

import com.wonglay.PersistenceService;
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 PersistenceService {
// equals方法
private static Method m1;
// toString方法
private static Method m2;
// save方法
private static Method m4;
// load方法
private static Method m3;
// hashCode方法
private static Method m0;

// 通过构造函数将为IocationHandler赋值
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);
}
}
// 调用InvocationHandler(PersistenceServiceInvocationHandler)的invoke方法
public final void save(Long var1, String var2) throws {
try {
super.h.invoke(this, m4, new Object[]{var1, var2});
} catch (RuntimeException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
// 调用InvocationHandler的invoke方法
public final String load(Long var1) throws {
try {
return (String)super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}

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);
}
}

// JVM加载此类时会初始化这段代码
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
// 得到PersistenceService的save方法对象
m4 = Class.forName("com.wonglay.PersistenceService").getMethod("save", Class.forName("java.lang.Long"), Class.forName("java.lang.String"));
// 得到PersistenceService的load方法对象
m3 = Class.forName("com.wonglay.PersistenceService").getMethod("load", Class.forName("java.lang.Long"));
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.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
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);

final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
// 这里生成代理类通过类加载器和接口生成代理类
Class<?> cl = getProxyClass0(loader, intfs);

try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}

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;
}
});
}
/**
* 调用代理类的构造方法,构造方法的参数就是InvocationHandler对象
* 对应代理对象的构造方法
* public $Proxy0(InvocationHandler var1) throws {
* super(var1);
* }
*/
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}

继续看这一行代代码 Class<?> cl = getProxyClass0(loader, intfs),点进去会看到如下方法,会先从一个叫WeakCache的缓存类获取代理类,如果获取不到在创建代理类,这个缓存对象是Proxy类的一个成员变量,在JVM加载Proxy类时就会执行赋值操作。

1
2
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

WeakCache类中获取代理对象的方法如下:

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
public V get(K key, P parameter) {
Objects.requireNonNull(parameter);
expungeStaleEntries();
Object cacheKey = CacheKey.valueOf(key, refQueue);
// lazily install the 2nd level valuesMap for the particular cacheKey
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
if (valuesMap == null) {
ConcurrentMap<Object, Supplier<V>> oldValuesMap
= map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap<>());
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
// create subKey and retrieve the possible Supplier<V> stored by that
// subKey from valuesMap
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
// 直到获取到代理对象才会返回
while (true) {
if (supplier != null) {
// supplier might be a Factory or a CacheValue<V> instance
// 可能是存在的实例,也可能是Factory生成的实例
V value = supplier.get();
if (value != null) {
return value;
}
}
// 如果创建代理类的工厂为null则创建
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
//如果代理工厂为null 赋值代理工厂
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
// successfully installed Factory
supplier = factory;
}
// else retry with winning supplier
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
// successfully replaced
// cleared CacheEntry / unsuccessful Factory
// with our Factory
supplier = factory;
} else {
// retry with current supplier
supplier = valuesMap.get(subKey);
}
}
}
}

接下来再看下代理工厂是怎么生成代理类的,如下是ProxyClassFactory的代码:

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
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// 代理对象类名前缀
private static final String proxyClassNamePrefix = "$Proxy";
// 代理对象类名后缀
private static final AtomicLong nextUniqueNumber = new AtomicLong();

@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
// 验证类加载器是否将此接口的名称解析为相同的类对象,因为在JVM中一个类是由类本身和类加载器共同决定
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
// 判断是否是接口,必须是接口才可以
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
// 接口不能重复
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
// 校验所有非public修饰的接口在同一包下,以便生成的代理类在同一包下
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) {
// 如果都是public修饰的接口生成的代理类会在com.sun.proxy下,否则为接口所在的包下
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
// 生成类全名
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
// 生成代理
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
}

以上就是整个对JDK动态代理实现原理的分析。

总结

诚然,Proxy 已经设计得非常优美,但是还是有一点点小小的遗憾之处,那就是它始终无法摆脱仅支持 interface 代理的桎梏,因为它的设计注定了这个遗憾。回想一下那些动态生成的代理类的继承关系图,它们已经注定有一个共同的父类叫 Proxy。Java 的继承机制注定了这些动态代理类们无法实现对 class 的动态代理,原因是多继承在 Java 中本质上就行不通。

有很多条理由,人们可以否定对 class 代理的必要性,但是同样有一些理由,相信支持 class 动态代理会更美好。接口和类的划分,本就不是很明显,只是到了 Java 中才变得如此的细化。如果只从方法的声明及是否被定义来考量,有一种两者的混合体,它的名字叫抽象类。实现对抽象类的动态代理,相信也有其内在的价值。此外,还有一些历史遗留的类,它们将因为没有实现任何接口而从此与动态代理永世无缘。如此种种,不得不说是一个小小的遗憾。但是如果必须代理类,CGLIB是一个不错的选择。

Author: wonglay
Link: https://wonglay.com/2021/01/01/jdk-dynamic-proxy-implementation-principle/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.