注:本文代码基于JDK 17
一、概述
动态代理,一个听起来很高深的名词,其实并非如此,在日常的开发中,你或多或少都有遇到过,比如你调用第三方SDK的方法时,该方法的具体实现或许就是使用了动态代理,这个本文后面会讲到。
不管是在Java开发还是Android开发中,动态代理的应用场景都非常广泛,因此我们需要学习它,并且了解它的运行原理,这也是本文接下来要做的事情。
二、什么是代理?
代理在我们的日常生活中很常见,比如说:
-
恶略天气出去吃饭麻烦,可以点外卖
-
爷爷不会使用手机充话费,找孙女帮忙充
在这两个例子中,外卖骑手、孙女这两个角色都是帮我们干活的,他们做着我们不能做或不想做的事情。
因此,代理其实就是当前对象不能做或不想做的事情,委托给别的对象做。
三、静态代理的使用
还是以上面的“孙女帮爷爷充话费”为例进行说明,现有一个行为接口Action,包含了一个充话费的方法recharge。
1
2
3
4
5
6
7
8
9
10
|
/**
* 行为接口
*/
public interface Action {
/**
* 充话费
*/
void recharge();
}
|
因为爷爷需要充话费,所以Grandfather类实现了Action接口。
1
2
3
4
5
6
7
8
9
10
|
/**
* 爷爷
*/
public final class Grandfather implements Action {
@Override
public void recharge() {
System.out.println("recharge");
}
}
|
但是,爷爷并不会使用手机充话费,于是他找了孙女请求帮忙充话费,那么Granddaughter类也要实现Action接口,然后把两者的充话费行为关联起来。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/**
* 孙女
*/
public final class Granddaughter implements Action {
private final Action action;
public Granddaughter(Action action) {
this.action = action;
}
@Override
public void recharge() {
System.out.println("before recharge");
if (action != null) action.recharge();
System.out.println("after recharge");
}
}
|
最终的main方法如下:
1
2
3
4
5
6
7
8
|
public class Client {
public static void main(String[] args) {
Grandfather grandfather = new Grandfather();
Granddaughter granddaughter = new Granddaughter(grandfather);
granddaughter.recharge();
}
}
|
由上面代码可知,Grandfather和Granddaughter两个类都实现了相同的接口Action,实际对象是Grandfather,代理对象是Granddaughter。
Granddaughter内部有一个action的成员变量,指向实际对象,在构造方法中被初始化,对于方法recharge方法的调用,它转发给了实际对象,接着在调用前后输出了一些跟踪调试信息,这也是代理对原方法进行增强的一种体现,上面代码输出如下:
1
2
3
|
before recharge
recharge
after recharge
|
因此,代理背后一般至少有一个实际对象,代理的外部功能和实际对象一般是一样的,用户与代理打交道,不直接接触实际对象。
在代码中创建了一个代理类Granddaughter,它的代码是在写程序时固定的,所以称为静态代理。
虽然静态代理实现简单,且不侵入原代码,但是当场景复杂一些的时候,静态代理的缺点也会暴露出来。
1、当需要代理多个类的时候,由于代理对象要实现与目标对象一致的接口,有2种方式:
- 只维护一个代理类,由这个代理类实现多个接口,但是这样就导致代理类过于庞大
- 新建多个代理类,每个目标对象对应一个代理类,但是这样会产生过多的代理类
2、当接口增加、删除、修改方法的时候,目标对象与代理类都要同时修改,十分不易维护。
那么,这要如何改进呢?
当然是让代理类动态的生成,这也是接下来要说的动态代理。
四、动态代理的使用
在静态代理中,代理类是直接定义在代码中的,而在动态代理中,代理类是动态生成的,那么就有一个疑问了,要如何去实现动态代理呢?
在JDK中,提供了java.lang.reflect.Proxy
和java.lang.reflect.InvocationHandler
这两个类来实现动态代理。动态代理的使用有2个步骤:
接下来,我们按照上面的步骤一一实现动态代理,首先创建一个类ActionInvocationHandler,让它去实现InvocationHandler接口,并且实现该接口的invoke方法,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
/**
* Action接口调用处理器
*/
public class ActionInvocationHandler implements InvocationHandler {
private final Object realObj; // 实际对象
public ActionInvocationHandler(Object realObj) {
this.realObj = realObj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before recharge");
Object result = method.invoke(realObj, args);
System.out.println("after recharge");
return result;
}
}
|
ActionInvocationHandler类实现了InvocationHandler接口,它的构造方法接受一个Object类型的参数realObj,realObj表示被代理的实际对象,接着在invoke方法中处理所有的接口调用,它有3个参数:
上面调用了method的invoke方法,传递了实际对象realObj作为参数,达到了调用实际对象对应方法的目的,在调用任何方法前后,我们输出了跟踪调试语句。需要注意的是,不能将proxy作为参数传递给method的invoke方法,比如:
1
|
Object result = method.invoke(proxy, args);
|
上面的语句会造成死循环,因为proxy表示当前代理对象,这又会调用到ActionInvocationHandler的invoke方法。
然后使用Proxy类的newProxyInstance方法去创建代理类的实例对象,调用代理类的实例对象的方法,代码如下:
1
2
3
4
5
6
7
8
9
|
public class Client {
public static void main(String[] args) {
Grandfather grandfather = new Grandfather();
Action action = (Action) Proxy.newProxyInstance(Action.class.getClassLoader(), new Class<?>[]{Action.class},
new ActionInvocationHandler(grandfather));
action.recharge();
}
}
|
和静态代理相比,代码看起来复杂不少,但是Action接口和Grandfather的定义不变,程序的输出也没变,只是代理对象Granddaughter的创建方式变了,它使用Proxy类的静态方法newProxyInstance来创建代理对象,该方法的声明如下:
1
2
3
|
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
|
newProxyInstance方法有3个参数:
newProxyInstance方法的返回值类型为Object,可以强制转换为interfaces数组中的某个接口类型。这里我们强制转换为了Action类型,需要注意的是,它不能强制转换为某个类类型。
如果上面动态代理的代码令你感到疑惑,那么接下来让我们一起去深入源码,慢慢解开你心中的疑惑。
五、动态代理的原理
我们先看下Proxy类的newProxyInstance方法,因为它返回的是代理类的实例对象,那么代理类的实例对象是怎么被构造出来的呢?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h) {
Objects.requireNonNull(h);
// 如果没有调用setSecurityManager方法设置SecurityManager,那么getSecurityManager方法返回为null,因此,默认情况下caller即为null,否则返回调用此方法的方法的调用者的类
@SuppressWarnings("removal")
final Class<?> caller = System.getSecurityManager() == null
? null
: Reflection.getCallerClass();
/*
* Look up or generate the designated proxy class and its constructor.
*/
// 分析1
Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);
// 分析2
return newProxyInstance(caller, cons, h);
}
|
分析1:调用getProxyConstructor方法创建代理类的构造方法所对应的构造器对象cons,
其中方法的参数传入了类加载器loader和数组interfaces;
分析2:调用newProxyInstance方法创建代理类的实例对象并返回,其中方法的参数传入了构造器对象cons和InvocationHandler类型的变量h。
OK,首先看getProxyConstructor方法的实现,它是怎么创建的构造器对象cons?
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
|
private static Constructor<?> getProxyConstructor(Class<?> caller,
ClassLoader loader,
Class<?>... interfaces)
{
// optimization for single interface
// 代理接口数组中只有单个接口
if (interfaces.length == 1) {
Class<?> intf = interfaces[0];
// 默认情况下,caller为null,不满足此处if
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();
// 默认情况下,caller为null,不满足此处if
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()
);
}
}
|
通过上面代码可知,根据数组interfaces的长度来分情况处理,但是不管怎样,最终都是调用了proxyCache变量的复杂调用链进行相关操作,那么proxyCache是什么玩意?
1
2
3
4
5
6
7
8
|
public class Proxy implements java.io.Serializable {
/**
* a cache of proxy constructors with
* {@link Constructor#setAccessible(boolean) accessible} flag already set
*/
private static final ClassLoaderValue<Constructor<?>> proxyCache =
new ClassLoaderValue<>();
}
|
由代码注释可知,proxyCache是已设置accessible标志的代理构造函数的缓存,并且它是ClassLoaderValue类型。跟踪ClassLoaderValue类发现它继承自抽象类AbstractClassLoaderValue,当调用ClassLoaderValue的sub方法时,因为ClassLoaderValue没有sub方法,所以实际上是调用了抽象类AbstractClassLoaderValue的sub方法,这个sub方法创建了Sub对象,而Sub类又是AbstractClassLoaderValue的内部类。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public abstract class AbstractClassLoaderValue<CLV extends AbstractClassLoaderValue<CLV, V>, V> {
public <K> Sub<K> sub(K key) {
return new Sub<>(key);
}
public final class Sub<K> extends AbstractClassLoaderValue<Sub<K>, V> {
private final K key;
Sub(K key) {
this.key = key;
}
}
}
|
根据proxyCache变量的复杂调用链,下一步就是调用Sub类的computeIfAbsent方法了,但是Sub类没有computeIfAbsent方法,那么调用的就是父类AbstractClassLoaderValue的computeIfAbsent方法了。
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 abstract class AbstractClassLoaderValue<CLV extends AbstractClassLoaderValue<CLV, V>, V> {
public V computeIfAbsent(ClassLoader cl,
BiFunction<
? super ClassLoader,
? super CLV,
? extends V
> mappingFunction) throws IllegalStateException {
ConcurrentHashMap<CLV, Object> map = map(cl);
@SuppressWarnings("unchecked")
CLV clv = (CLV) this;
Memoizer<CLV, V> mv = null;
while (true) {
Object val = (mv == null) ? map.get(clv) : map.putIfAbsent(clv, mv);
if (val == null) {
if (mv == null) {
// create Memoizer lazily when 1st needed and restart loop
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 {
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
}
}
}
|
computeIfAbsent方法当中用到了ConcurrentHashMap,这里可以知道应该是支持多线程并发的,computeIfAbsent方法的功能可以解读为:返回与此ClassLoaderValue和给定ClassLoader关联的值,如果不存在,则通过调用给定的mappingFunction来计算该值,将其关联并返回它。
很明显,map中没有缓存时,创建构造器的核心逻辑落在了在ProxyBuilder类上,继续跟踪ProxyBuilder类,发现它是Proxy的内部类,先看它的成员变量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public class Proxy implements java.io.Serializable {
private static final class ProxyBuilder {
// 分析1
private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
// 分析2:所有代理类名称的前缀
// prefix for all proxy class names
private static final String proxyClassNamePrefix = "$Proxy";
// 分析3:用于生成唯一代理类名称的下一个数字
// next number to use for generation of unique proxy class names
private static final AtomicLong nextUniqueNumber = new AtomicLong();
// 分析4:已定义代理类的反向缓存,也就是已经生成代理类的纪录为true
// a reverse cache of defined proxy classes
private static final ClassLoaderValue<Boolean> reverseProxyCache =
new ClassLoaderValue<>();
}
}
|
分析1:创建了JavaLangAccess实例,它是通过SharedSecrets的getJavaLangAccess方法来获取,我寻思既然有getXXX方法,那么也应该有setXXX方法,经过一番搜索,发现JavaLangAccess的setJavaLangAccess方法是在System类的setJavaLangAccess方法中被调用,而System类的setJavaLangAccess方法将通过虚拟机VM来调用。
1
2
3
4
5
6
7
8
9
10
11
12
|
private static void setJavaLangAccess() {
// Allow privileged classes outside of java.lang
SharedSecrets.setJavaLangAccess(new JavaLangAccess() {
// 埋下伏笔
public Class<?> defineClass(ClassLoader loader, String name, byte[] b, ProtectionDomain pd, String source) {
return ClassLoader.defineClass1(loader, name, b, 0, b.length, pd, source);
}
// ...
});
}
|
继续跟踪ProxyBuilder类的构造函数。
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
|
ProxyBuilder(ClassLoader loader, List<Class<?>> interfaces) {
// 分析2:如果模块系统未初始化,那么代理是不支持的
if (!VM.isModuleSystemInited()) {
throw new InternalError("Proxy is not supported until "
+ "module system is fully initialized");
}
// 分析3:代理接口数量最多只能65535个
if (interfaces.size() > 65535) {
throw new IllegalArgumentException("interface limit exceeded: "
+ interfaces.size());
}
// 分析4:返回代理接口的所有公共非静态方法签名引用的所有类型(返回值类型、共享参数类型,共享异常类型)
Set<Class<?>> refTypes = referencedTypes(loader, interfaces);
// 分析5:验证给定的代理接口和给定的引用类型对定义加载器可见
// IAE if violates any restrictions specified in newProxyInstance
validateProxyInterfaces(loader, interfaces, refTypes);
this.interfaces = interfaces;
// 分析6:返回生成的代理类所属的模块,有如下规则:
// 1、如果任何代理接口是包私有的,则代理类位于包私有接口的同一模块中
// 2、如果所有代理接口都是公共的并且位于导出包中,则代理类位于无条件导出包中的动态模块中
// 3、如果所有代理接口都是公共的,并且至少有一个位于非导出包中,则该代理类位于非导出包中的动态模块中
this.module = mapToModule(loader, interfaces, refTypes);
assert getLoader(module) == loader;
}
// 分析1:如果是单个代理接口的情况,其实也是把接口转换为List,然后调用另一个构造方法
ProxyBuilder(ClassLoader loader, Class<?> intf) {
this(loader, Collections.singletonList(intf));
}
|
由上面代码可知,代理类的生成有着许多限制规则,主要是Java 9引入了模块管理的概念,继续跟踪ProxyBuilder类的build方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
// 生成一个代理类并返回其代理构造函数,并已设置可访问标志
Constructor<?> build() {
// 分析1:定义代理类的Class对象
Class<?> proxyClass = defineProxyClass(module, interfaces);
assert !module.isNamed() || module.isOpen(proxyClass.getPackageName(), Prox
final Constructor<?> cons;
try {
// 分析2:返回代理类的构造器
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方法当中,继续跟踪。
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
|
private static Class<?> defineProxyClass(Module m, List<Class<?>> interfaces) {
// 分析1:定义代理类所在的包路径
String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
boolean nonExported = false;
/*
* 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.
*/
// 分析2:记录非公共代理接口的包,以便代理类将定义在同一个包中。验证所有非公共代理接口是否位于同一个包中。
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");
}
} else {
if (!intf.getModule().isExported(intf.getPackageName())) {
// module-private types
nonExported = true;
}
}
}
// 分析3:所有代理接口都是公共和导出的
if (proxyPkg == null) {
// all proxy interfaces are public and exported
if (!m.isNamed())
throw new InternalError("ununamed module: " + m);
// 如果代理接口所在包名在模块中是不可导出的,那么代理接口包名定义为com.sun.proxy.模块名,否则定义为模块名
proxyPkg = nonExported ? PROXY_PACKAGE_PREFIX + "." + m.getName()
: m.getName();
} 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.
*/
// 分析4:选择要生成的代理类的名称
// 计数器+1
long num = nextUniqueNumber.getAndIncrement();
// 如果包名为"",代理类名字 $Proxy + 计数器数字,否则 包名.$Proxy + 计数器数字
String proxyName = proxyPkg.isEmpty()
? proxyClassNamePrefix + num
: proxyPkg + "." + proxyClassNamePrefix + num;
ClassLoader loader = getLoader(m);
trace(proxyName, m, loader, interfaces);
/*
* Generate the specified proxy class.
*/
// 分析5:生成指定的代理类
// 动态生成代理类字节数组
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(loader, proxyName, interfaces, accessFlags);
try {
// 通过代理类字节数组定义代理类Class对象,对于了前面说的System的setJavaLangAccess方法的实现
Class<?> pc = JLA.defineClass(loader, proxyName, proxyClassFile,
null, "__dynamic_proxy__");
// 缓存代理类已经生成过的标记true
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());
}
}
|
继续跟踪ProxyGenerator的generateProxyClass方法,看看是如何生成代理类字节数组的。
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
|
// 给定名称和代理接口列表生成代理类
static byte[] generateProxyClass(ClassLoader loader,
final String name,
List<Class<?>> interfaces,
int accessFlags) {
// 分析1
ProxyGenerator gen = new ProxyGenerator(loader, name, interfaces, accessFlags);
final byte[] classFile = gen.generateClassFile();
// 分析2
if (saveGeneratedFiles) {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
try {
int i = name.lastIndexOf('.');
Path path;
if (i > 0) {
Path dir = Path.of(dotToSlash(name.substring(0, i)));
Files.createDirectories(dir);
path = dir.resolve(name.substring(i + 1) + ".class");
} else {
path = Path.of(name + ".class");
}
Files.write(path, classFile);
return null;
} catch (IOException e) {
throw new InternalError(
"I/O exception saving generated file: " + e);
}
}
});
}
return classFile;
}
|
分析1:调用了ProxyGenerator的generateClassFile方法来生成代理类的字节数组,跟踪看看。
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
|
// 生成代理类的类文件。该方法驱动类文件生成过程
private byte[] generateClassFile() {
// 确定代理类的基础信息(类修饰符、类名、父类、实现的接口等等)
visit(V14, accessFlags, dotToSlash(className), null,
JLR_PROXY, typeNames(interfaces));
/*
* Add proxy methods 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.
*/
// 分析1:将所有方法封装成ProxyMethod对象
// 为java.lang.Object的hashCode、equals和toString方法添加代理方法。这是在代理接口中的方法之前完成的,以便 java.lang.Object 中的方法优先于代理接口中的重复方法。
addProxyMethod(hashCodeMethod);
addProxyMethod(equalsMethod);
addProxyMethod(toStringMethod);
/*
* Accumulate all of the methods from the proxy interfaces.
*/
// 遍历所有代理接口中的所有方法,并生成ProxyMethod对象
for (Class<?> intf : interfaces) {
for (Method m : intf.getMethods()) {
if (!Modifier.isStatic(m.getModifiers())) {
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);
}
// 分析2:开始生成代理类的构造,方法,成员变量等等
// 生成代理类的构造方法
generateConstructor();
// 遍历ProxyMethod列表
for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
for (ProxyMethod pm : sigmethods) {
// add static field for the Method object
// 为Method对象添加静态字段
visitField(ACC_PRIVATE | ACC_STATIC | ACC_FINAL, pm.methodFieldName,
LJLR_METHOD, null, null);
// Generate code for proxy method
// 生成代理方法的代码
pm.generateMethod(this, className);
}
}
// 生成代理类的静态代码块
generateStaticInitializer();
generateLookupAccessor();
// 第一步:计算 ClassFile 结构的大小(以字节为单位)。 magic 字段使用 4 个字节,10 个强制字段(minor_version、major_version、constant_pool_count、access_flags、this_class、super_class、interfaces_count、fields_count、methods_count 和 attribute_count)每个使用 2 个字节,每个接口也使用 2 个字节。
// 第二步:分配一个正确大小的 ByteVector并用 ClassFile 内容填充它。
// 也就是写入魔数、次版本号、主版本号、常量池等等。
// 第三步:转换为二进制数组输出
return toByteArray();
}
|
分析2:saveGeneratedFiles是用于保存生成的代理类文件的调试标志,如下所示:
1
2
3
4
|
private static final boolean saveGeneratedFiles =
java.security.AccessController.doPrivileged(
new GetBooleanAction(
"jdk.proxy.ProxyGenerator.saveGeneratedFiles"));
|
AccessController的doPrivileged方法需要传入PrivilegedAction接口,而PrivilegedAction接口中有一个run方法,run方法的返回值即为saveGeneratedFiles,又因为GetBooleanAction实现了PrivilegedAction接口,所以只需跟踪GetBooleanAction的run方法即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public class GetBooleanAction
implements java.security.PrivilegedAction<Boolean> {
private String theProp;
/**
* Constructor that takes the name of the system property whose boolean
* value needs to be determined.
*
* @param theProp the name of the system property.
*/
public GetBooleanAction(String theProp) {
this.theProp = theProp;
}
public Boolean run() {
return Boolean.getBoolean(theProp);
}
}
|
继续跟踪Boolean的getBoolean方法。
1
2
3
4
5
6
7
8
|
public static boolean getBoolean(String name) {
boolean result = false;
try {
result = parseBoolean(System.getProperty(name));
} catch (IllegalArgumentException | NullPointerException e) {
}
return result;
}
|
很显然,调用了System类的getProperty方法,然后转换为boolean值返回,name其实就是
jdk.proxy.ProxyGenerator.saveGeneratedFiles
,那么我们只需要在Proxy类的newProxyInstance方法之前,通过System类的setProperty方法设置该值为true即可保存代理类文件。
1
2
3
4
5
6
7
8
9
10
|
public class Client {
public static void main(String[] args) {
System.setProperty("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");
Grandfather grandfather = new Grandfather();
Action action = (Action) Proxy.newProxyInstance(Action.class.getClassLoader(), new Class<?>[]{Action.class},
new ActionInvocationHandler(grandfather));
action.recharge();
}
}
|
运行过后,会在如下位置生成代理类,这也是接口都是public修饰时的情况。
本例中生成的代理类如下:
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
|
public final class $Proxy0 extends Proxy implements Action {
private static final Method m0;
private static final Method m1;
private static final Method m2;
private static final Method m3;
public $Proxy0(InvocationHandler var1) {
super(var1);
}
public final int hashCode() {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final boolean equals(Object var1) {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() {
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 recharge() {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
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.pengmj.proxy.Action").getMethod("recharge");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
private static MethodHandles.Lookup proxyClassLookup(MethodHandles.Lookup var0) throws IllegalAccessException {
if (var0.lookupClass() == Proxy.class && var0.hasFullPrivilegeAccess()) {
return MethodHandles.lookup();
} else {
throw new IllegalAccessException(var0.toString());
}
}
}
|
由上面代码可知:
1、代理类$Proxy0
继承自Proxy类,并实现了我们自己定义的Action接口;
有一个疑问:问什么JDK动态代理只能基于接口进行代理?
因为它已经继承了Proxy类了,而Java不支持多继承。
2、代理类使用了final修饰,说明代理类无法被继承;
3、接口中所有被代理的方法以及Object类的hashCode、equals、toString方法在static静态代码块中通过反射建立了method对象;
4、当调用接口中所有被代理的方法以及Object类的hashCode、equals、toString方法时,都会转交给InvocationHandler的invoke方法;
我们回到之前流程,当创建了代理类的构造器之后,就会调用newProxyInstance方法,继续跟踪看看。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
private static Object newProxyInstance(Class<?> caller, // null if no SecurityManager
Constructor<?> cons,
InvocationHandler h) {
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (caller != null) {
checkNewProxyPermission(caller, cons.getDeclaringClass());
}
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);
}
}
}
|
很明显了,通过构造器直接newInstance创建代理类实例对象,构造方法传入的参数为h。至此,JDK动态代理的原理就讲解完成了。
六、动态代理在Android上的运用
在Android上,动态代理也隐隐约约地存在着,比如网络请求框架Retrofit,它的create方法就使用了动态代理。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
public <T> T create(final Class<T> service) {
validateServiceInterface(service);
return (T)
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
|