Proxy 1.8
以下源码分析取核心代码
变量定义
1 | /** parameter types of a proxy class constructor */ |
根据注释很容易理解,1.8在1.7基础上优化代码,依然是弱引用做为缓存。key和value都采用工厂模式。
KeyFactory
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17/**
* A function that maps an array of interfaces to an optimal key where
* Class objects representing interfaces are weakly referenced.
*/
private static final class KeyFactory
implements BiFunction<ClassLoader, Class<?>[], Object>
{
@Override
public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
switch (interfaces.length) {
case 1: return new Key1(interfaces[0]); // the most frequent
case 2: return new Key2(interfaces[0], interfaces[1]);
case 0: return key0;
default: return new KeyX(interfaces);
}
}
}根据上下文代码及注释,可以知道这是工厂模式。
- 实现
BiFunction
函数,BiFunction
是函数式接口。 Key1
、Key2
、KeyX
,代表接口数量。分别是1个接口、2个接口、多个接口。
Key1、Key2、KeyX
1 | /* |
- 0个接口,proxy class的key。
- 同3。
Key1
,Key2
是proxy class实现1个接口、2个接口的实现。- 第2个接口的弱引用对象。
Key3
是proxy class实现3个以上接口。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
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/**
1. A factory function that generates, defines and returns the proxy class given
2. the ClassLoader and array of interfaces.
*/
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// prefix for all proxy class names
private static final String proxyClassNamePrefix = "$Proxy";
// next number to use for generation of unique proxy class names
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
// #1
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
/*
* Verify that the class loader resolves the name of this
* interface to the same Class object.
*/
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");
}
/*
* Verify that the Class object actually represents an
* interface.
*/
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
/*
* Verify that this interface is not a duplicate.
*/
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;
/*
* 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;
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) {
// if no non-public proxy interfaces, use com.sun.proxy package
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
/*
* Choose a name for the proxy class to generate.
*/
// #3
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* Generate the specified proxy class.
*/
// #4
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} 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());
}
}
}IdentityHashMap
存储接口class,并且做interfaceclass
验效。- 验证非public接口的package是不是都是在同一个package下。
- 根据原子特性,生成
proxy name
,proxy name
规则是序号递增的。 ProxyGenerator
是sun.misc
包下的,生成proxy class的字节码。由以上得知Java动态代理只能代理接口。
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
52public 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);
}
/*
* Look up or generate the designated proxy class.
*/
// #1
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
// #2
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;
}
});
}
// #3
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);
}
}生成proxy class,
cl = class com.sun.proxy.$Proxy0
。这里$Proxy0
对象是临时生成,没有java、class(第6会说明)文件。cl.getConstructor(constructorParams)
实际上就是com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler)
。生成proxy class实例化对象。
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
31private static final boolean saveGeneratedFiles = (Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"));
public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
final byte[] var4 = var3.generateClassFile();
// #1
if (saveGeneratedFiles) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
try {
int var1 = var0.lastIndexOf(46);
Path var2;
if (var1 > 0) {
Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
Files.createDirectories(var3);
var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
} else {
var2 = Paths.get(var0 + ".class");
}
// #2
Files.write(var2, var4, new OpenOption[0]);
return null;
} catch (IOException var4x) {
throw new InternalError("I/O exception saving generated file: " + var4x);
}
}
});
}
return var4;
}判断是否存储proxy class字节码
$Proxy0
到磁盘。- 输出流,保存到磁盘。
proxy class字节码写入磁盘
demo1
根据ProxyGenerator#generateProxyClass#saveGeneratedFiles
,可以把saveGeneratedFiles
设置为true。在磁盘上(项目路径下)会生成$Proxy0.class
文件。1
2// #1
private static final boolean saveGeneratedFiles = (Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"));
1 | public static boolean getBoolean(String name) { |
1 | // #2 |
GetBooleanAction#run
,从Boolean#getBoolean
获取值,从Boolean#getBoolean
可以知道,最终调用的System.getProperty(name)
。- 由1知道,所以我们这里设置
saveGeneratedFiles = true
。注意jdk1.8.0_161设置String = true
才生效。完整代码例子
Mammal
1
2
3
4
5//接口1:Mammal(哺乳动物)
public interface Mammal {
void eat(String food);
String type();
}
Primate
1 | //接口2:Primate(灵长类动物) |
Monkey
1 | //实现类:Monkey |
MyInvocationHandler
1 | public class MyInvocationHandler implements InvocationHandler { |
Main
1 | public class Main { |
method = public abstract void demo1.Primate.think()
,method接口方法;obj=Monkey@663
,obj是实现类的对象。这里通过反射调用方法。c = com.sun.proxy.$Proxy0
,在项目目录下生成的代理类对象。- 动态代理生成方式一,
proxy1 = ($Proxy@667)Monkey@2b80d80f
,动态Proxy Class对象。 - 同上,
proxyClass = class com.sun.proxy.$Proxy0,proxy2 = ($Proxy@685)Monkey@3ab39c39
,动态Proxy Class对象。 - 同上
saveGeneratedFiles
设置为true,默认会写入磁盘。proxy0.class另一种方式写入磁盘
code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 获取代理类的字节码
byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy11", Monkey.class.getInterfaces());
FileOutputStream out = null;
try {
out = new FileOutputStream(path);
out.write(classFile);
out.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
分析$Proxy.class
1 | package com.sun.proxy; |
$Proxy0
继承Proxy
,实现Mammal
,Primate
接口。- 这里是
$Proxy0
的构造函数,是前文提到的cl.getConstructor(constructorParams)
。 - 就是调用
MyInvocationHandler
的public Object invoke(Object proxy, Method method, Object[] args)
。根据上文例子:1
2Mammal mammal = (Mammal) proxy2;
mammal.type()实际上就是调用();
type()
实际上就是调用MyInvocationHandler#invoke
。