JDK1.7 Proxy

Proxy 1.7

以下源码分析取核心代码

1 变量定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
   /** prefix for all proxy class names */
// #1
private final static String proxyClassNamePrefix = "$Proxy";

/** parameter types of a proxy class constructor */
private final static Class[] constructorParams =
{ InvocationHandler.class };

/** maps a class loader to the proxy class cache for that loader */
// #2
private static Map loaderToCache = new WeakHashMap();

/** marks that a particular proxy class is currently being generated */
// #3
private static Object pendingGenerationMarker = new Object();

/** next number to use for generation of unique proxy class names */
private static long nextUniqueNumber = 0;
private static Object nextUniqueNumberLock = new Object();

/** set of all generated proxy classes, for isProxyClass implementation */
// #4
private static Map proxyClasses = Collections.synchronizedMap(new WeakHashMap());

标注代码分析:

  1. 定义代理类名字前缀。
  2. 定义弱引用,以ClassLoader loader做为key,定义一个class load 缓存。
  3. 为了生成代理类,初始化的cache时候,一直存在的“临时”对象。
  4. proxyClass的缓存,key存储proxy class,value存储null,用于判断是否是代理类。

    2 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)
    .....

    /*
    5. Look up or generate the designated proxy class.
    */
    // #1
    Class cl = getProxyClass(loader, interfaces);

    /*
    6. Invoke its constructor with the designated invocation handler.
    */
    try {
    // #2
    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());
    }
    }
  5. 生成proxy class的$Proxy0

  6. 生成$Proxy0的构造函数。

3 getProxyClass

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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
  public static Class<?> getProxyClass(ClassLoader loader,  Class<?>... interfaces) throws IllegalArgumentException
{
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
Class proxyClass = null;

/* collect interface names to use as key for proxy class cache */
// #1
String[] interfaceNames = new String[interfaces.length];

Set interfaceSet = new HashSet(); // for detecting duplicates

for (int i = 0; i < interfaces.length; i++) {
/*
* Verify that the class loader resolves the name of this
* interface to the same Class object.
*/

String interfaceName = interfaces[i].getName();

Class interfaceClass = null;
try {
// #2
interfaceClass = Class.forName(interfaceName, false, loader);
} catch (ClassNotFoundException e) {
}
// #3
if (interfaceClass != interfaces[i]) {
throw new IllegalArgumentException(
interfaces[i] + " 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.
*/
// #4
if (interfaceSet.contains(interfaceClass)) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}

interfaceSet.add(interfaceClass);

interfaceNames[i] = interfaceName;
}

/*
* Using string representations of the proxy interfaces as
* keys in the proxy class cache (instead of their Class
* objects) is sufficient because we require the proxy
* interfaces to be resolvable by name through the supplied
* class loader, and it has the advantage that using a string
* representation of a class makes for an implicit weak
* reference to the class.
*/
Object key = Arrays.asList(interfaceNames);

/*
* Find or create the proxy class cache for the class loader.
*/
Map cache;
// #5
synchronized (loaderToCache) {
// #6
cache = (Map) loaderToCache.get(loader);
if (cache == null) {
cache = new HashMap();
loaderToCache.put(loader, cache);
}
/*
* This mapping will remain valid for the duration of this
* method, without further synchronization, because the mapping
* will only be removed if the class loader becomes unreachable.
*/
}

/*
* Look up the list of interfaces in the proxy class cache using
* the key. This lookup will result in one of three possible
* kinds of values:
* null, if there is currently no proxy class for the list of
* interfaces in the class loader,
* the pendingGenerationMarker object, if a proxy class for the
* list of interfaces is currently being generated,
* or a weak reference to a Class object, if a proxy class for
* the list of interfaces has already been generated.
*/
// #7
synchronized (cache) {
/*
* Note that we need not worry about reaping the cache for
* entries with cleared weak references because if a proxy class
* has been garbage collected, its class loader will have been
* garbage collected as well, so the entire cache will be reaped
* from the loaderToCache map.
*/
do {
// #8
Object value = cache.get(key);
if (value instanceof Reference) {
proxyClass = (Class) ((Reference) value).get();
}
if (proxyClass != null) {
// proxy class already generated: return it
return proxyClass;
// #9
} else if (value == pendingGenerationMarker) {
// proxy class being generated: wait for it
try {
cache.wait();
} catch (InterruptedException e) {
/*
* The class generation that we are waiting for should
* take a small, bounded time, so we can safely ignore
* thread interrupts here.
*/
}
continue;
} else {
/*
* No proxy class for this list of interfaces has been
* generated or is being generated, so we will go and
* generate it now. Mark it as pending generation.
*/
// #10
cache.put(key, pendingGenerationMarker);
break;
}
} while (true);
}

try {

String proxyPkg = null; // package to define proxy class in

/*
* 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.
*/
for (int i = 0; i < interfaces.length; i++) {
int flags = interfaces[i].getModifiers();
if (!Modifier.isPublic(flags)) {
String name = interfaces[i].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,
proxyPkg = ""; // use the unnamed package
}

{
/*
* Choose a name for the proxy class to generate.
*/
long num;
synchronized (nextUniqueNumberLock) {
num = nextUniqueNumber++;
}
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* Verify that the class loader hasn't already
* defined a class with the chosen name.
*/

/*
* Generate the specified proxy class.
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces);
try {
//native
proxyClass = 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());
}
}
// add to set of all generated proxy classes, for isProxyClass
// #11
proxyClasses.put(proxyClass, null);

} finally {
/*
* We must clean up the "pending generation" state of the proxy
* class cache entry somehow. If a proxy class was successfully
* generated, store it in the cache (with a weak reference);
* otherwise, remove the reserved entry. In all cases, notify
* all waiters on reserved entries in this cache.
*/
// #12
synchronized (cache) {
if (proxyClass != null) {
cache.put(key, new WeakReference(proxyClass));
} else {
cache.remove(key);
}
cache.notifyAll();
}
}
return proxyClass;
}

标注代码分析:

  1. 接口数组做为缓存的key。
  2. proxy接口的class。
  3. 验证1。
  4. 验证2,检查proxyClass接口重复性,已经重复的接口不再放入interfaceNames数组中。
  5. 同步ClassLoader缓存,查询loader的缓存集合。
  6. 根据ClassLoader查找缓存。
  7. cache是loader的缓存集合,同步代码块里cache获取proxyClass
  8. 缓存对象value,此时的value,有可能是Object(pendingGenerationMarker)或者WeakReference对象,后续根据不同的value值,进行不同逻辑判断。
  9. 因为初始化对象是pendingGenerationMarker,此时value对象相等,说明正在生成proxyClass对象,进行等待,结束本次循环。
  10. proxyClass is null,cache初始化默认value值pendingGenerationMarker
  11. proxyClass创建完毕,放入缓存。
  12. proxyClass创建失败,清除cache中value = pendingGenerationMarker的值。

由以上得知Java动态代理只能代理接口。

4 Other Code

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
/**
* Returns an instance of a proxy class for the specified interfaces
* that dispatches method invocations to the specified invocation
* handler. This method is equivalent to:
* <pre>
* Proxy.getProxyClass(loader, interfaces).
* getConstructor(new Class[] { InvocationHandler.class }).
* newInstance(new Object[] { handler });
* </pre>
*
* <p><code>Proxy.newProxyInstance</code> throws
* <code>IllegalArgumentException</code> for the same reasons that
* <code>Proxy.getProxyClass</code> does.
*
* @param loader the class loader to define the proxy class
* @param interfaces the list of interfaces for the proxy class
* to implement
* @param h the invocation handler to dispatch method invocations to
* @return a proxy instance with the specified invocation handler of a
* proxy class that is defined by the specified class loader
* and that implements the specified interfaces
* @throws IllegalArgumentException if any of the restrictions on the
* parameters that may be passed to <code>getProxyClass</code>
* are violated
* @throws NullPointerException if the <code>interfaces</code> array
* argument or any of its elements are <code>null</code>, or
* if the invocation handler, <code>h</code>, is
* <code>null</code>
*/
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
if (h == null) {
throw new NullPointerException();
}

/*
* Look up or generate the designated proxy class.
*/
// #1
Class cl = getProxyClass(loader, interfaces);

/*
* Invoke its constructor with the designated invocation handler.
*/
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());
}
}

/**
* Returns true if and only if the specified class was dynamically
* generated to be a proxy class using the <code>getProxyClass</code>
* method or the <code>newProxyInstance</code> method.
*
* <p>The reliability of this method is important for the ability
* to use it to make security decisions, so its implementation should
* not just test if the class in question extends <code>Proxy</code>.
*
* @param cl the class to test
* @return <code>true</code> if the class is a proxy class and
* <code>false</code> otherwise
* @throws NullPointerException if <code>cl</code> is <code>null</code>
*/
public static boolean isProxyClass(Class<?> cl) {
if (cl == null) {
throw new NullPointerException();
}

return proxyClasses.containsKey(cl);
}

标注代码分析:

  1. 生成指定接口的proxClass对象。

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×