最近在学习java中的设计模式,学到代理模式的时候,发现动态代理的确比较强大,然后就针对JDK中的Proxy的实现原理进行了研究,Proxy类的主要目的就是根据用户提供的信息自动生成一个代理类,当然也提供了生成代理类实例的接口,而这个类最核心的东西就是根据用户提供接口动态创建一个代理类,这也是个人感觉Proxy设计的高深之处。所以就想写下来全当加深理解和记忆。
这里主要就讨论Proxy是如何根据用户提供的接口列表动态生成一个相应的代理类的。
这个问题的答案全在getProxyClass0函数之中,这里我们就只对这个函数进行剖析,原理基本就高搞清了。好,照着源码分析:
private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces)
loader,是用来创建和保存对应的代理类的类加载器,我们知道,java中的任何类都是要一个ClassLoader加载对应的字节码到内存中,然后才能使用的,因此要动态一个类,也离不了类加载器。
interfaces,这个参数数组是要创建的代理类要代理的所有接口列表,注意:这里的接口是Interface,不是function,本人刚开始看的时候就因此迷糊了好久。也就是说,这里创建的一个代理类可以为多个Interface提供代理,根据代理模式的定义,本来代理就是以类/接口为单位的,所以说,切忌不要认为这里的Interface是函数。至于为什么是接口而不是类,后面具体分析的时候会具体说明。
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
这个判断用来限制被代理的接口数量不能超过最大限制。
1 Class<?> proxyClass = null;
2
3 /* collect interface names to use as key for proxy class cache */
4 String[] interfaceNames = new String[interfaces.length];
5
6 // for detecting duplicates
7 Set<Class<?>> interfaceSet = new HashSet<>();
8
上述代码定义了要创建的代理类,要代理的接口数组以及接口对应的结合,以备下面使用
9 for (int i = 0; i < interfaces.length; i++) {
10 /*
11 * Verify that the class loader resolves the name of this
12 * interface to the same Class object.
13 */
14 String interfaceName = interfaces[i].getName();
15 Class<?> interfaceClass = null;
16 try {
17 interfaceClass = Class.forName(interfaceName, false, loader);
18 } catch (ClassNotFoundException e) {
19 }
20 if (interfaceClass != interfaces[i]) {
21 throw new IllegalArgumentException(
22 interfaces[i] + " is not visible from class loader");
23 }
上述代码验证当前接口是在传入的ClassLoader可见,因为,只有可见才能用改加载器来创建并加载相应的接口代码,主要就是Class.forName(interfaceName, false, loader);Class.forName函数用给定的ClassLoader返回与给定的类或者接口相关联的一个Class 对象。如果该函数执行失败,则意味着当前interfaceName在
给定的loader是不可见的。
24
25 /*
26 * Verify that the Class object actually represents an
27 * interface.
28 */
29 if (!interfaceClass.isInterface()) {
30 throw new IllegalArgumentException(
31 interfaceClass.getName() + " is not an interface");
32 }
验证当前接口是否真正的接口,因为传入的参数是Class<?>[],因此如果传了一个类进来也是可以的,因此,这一步的验证也是不可缺少。
33
34 /*
35 * Verify that this interface is not a duplicate.
36 */
37 if (interfaceSet.contains(interfaceClass)) {
38 throw new IllegalArgumentException(
39 "repeated interface: " + interfaceClass.getName());
40 }
41 interfaceSet.add(interfaceClass);
42
43 interfaceNames[i] = interfaceName;
44 }
确保没有传入重复的接口,因为如果接口重复,就意味着要在即将创建的代理类中为同一个接口的函数提供两套实现,这是非法的,因此需要验证。
45
46 /*
47 * Using string representations of the proxy interfaces as
48 * keys in the proxy class cache (instead of their Class
49 * objects) is sufficient because we require the proxy
50 * interfaces to be resolvable by name through the supplied
51 * class loader, and it has the advantage that using a string
52 * representation of a class makes for an implicit weak
53 * reference to the class.
54 */
55 List<String> key = Arrays.asList(interfaceNames);
这里创建当前传入接口的一个List,从变量名可以看到将在作为Key来使用,后面会看到如何使用
56
57 /*
58 * Find or create the proxy class cache for the class loader.
59 */
60 Map<List<String>, Object> cache;
这里创建当前一个临时的缓存项,针对当前的类加载器,这个缓存的key就是上一步创建的List,value就是每个被创建的代理类。
插入一段:
private static Map<ClassLoader, Map<List<String>, Object>> loaderToCache
= new WeakHashMap<>();
这个就是Proxy类内部用来存放所有ClassLoader对应的代理类的缓存
61 synchronized (loaderToCache) {
62 cache = loaderToCache.get(loader);
63 if (cache == null) {
64 cache = new HashMap<>();
65 loaderToCache.put(loader, cache);
66 }
67 /*
68 * This mapping will remain valid for the duration of this
69 * method, without further synchronization, because the mapping
70 * will only be removed if the class loader becomes unreachable.
71 */
72 }
上述代码首先对laoderToCache加锁,因为涉及到多线程同时访问该变量,因此加锁是必须的。然后试图获取当前ClassLoader对应的代理类缓存,如果为空,
则直接创建,并加入到laoderToCache中。然后就是从对应的代理类缓冲中去查找当前接口集合对应的代理类。查找的结果有三种:Null,pendingGenerationMarker(正在被创建),a weak reference(已经创建好的代理类的引用)
73
74 /*
75 * Look up the list of interfaces in the proxy class cache using
76 * the key. This lookup will result in one of three possible
77 * kinds of values:
78 * null, if there is currently no proxy class for the list of
79 * interfaces in the class loader,
80 * the pendingGenerationMarker object, if a proxy class for the
81 * list of interfaces is currently being generated,
82 * or a weak reference to a Class object, if a proxy class for
83 * the list of interfaces has already been generated.
84 */
85 synchronized (cache) {
86 /*
87 * Note that we need not worry about reaping the cache for
88 * entries with cleared weak references because if a proxy class
89 * has been garbage collected, its class loader will have been
90 * garbage collected as well, so the entire cache will be reaped
91 * from the loaderToCache map.
92 */
93 do {
94 Object value = cache.get(key);
95 if (value instanceof Reference) {
96 proxyClass = (Class<?>) ((Reference) value).get();
97 }
98 if (proxyClass != null) {//代理类已经被创建
99 // proxy class already generated: return it
100 return proxyClass;
101 } else if (value == pendingGenerationMarker) {
102 // proxy class being generated: wait for it
103 try {//代理类正在被创建,等待,直到创建完成,进入上面if返回
104 cache.wait();
105 } catch (InterruptedException e) {
106 /*
107 * The class generation that we are waiting for should
108 * take a small, bounded time, so we can safely ignore
109 * thread interrupts here.
110 */
111 }
112 continue;
113 } else {
114 /*
115 * No proxy class for this list of interfaces has been
116 * generated or is being generated, so we will go and
117 * generate it now. Mark it as pending generation.
118 */
代理类尚未被创建,也不处于正在被创建状态,则设置为正在被创建标识,退出查找,并开始真正的创建工作
119 cache.put(key, pendingGenerationMarker);
120 break;
<pre class="java" name="code"> 121 }
122 } while (true);
123 }
124
125 try {
126 String proxyPkg = null; // package to define proxy class in
127
128 /*
129 * Record the package of a non-public proxy interface so that the
130 * proxy class will be defined in the same package. Verify that
131 * all non-public proxy interfaces are in the same package.
132 */
133 for (int i = 0; i < interfaces.length; i++) {
134 int flags = interfaces[i].getModifiers();
135 if (!Modifier.isPublic(flags)) {
136 String name = interfaces[i].getName();
137 int n = name.lastIndexOf('.');
138 String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
139 if (proxyPkg == null) {
140 proxyPkg = pkg;
141 } else if (!pkg.equals(proxyPkg)) {
142 throw new IllegalArgumentException(
143 "non-public interfaces from different packages");
144 }
145 }
146 }
147
上面这段代码做了两件事情:第一:验证是否所有非public的接口位于同一个package,否则抛出异常;第二:组装代理类的包名
148 if (proxyPkg == null) {
149 // if no non-public proxy interfaces, use com.sun.proxy package
150 proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
151 }
如果所有的接口都是public的,则代理类包名被指定为com.sun.proxy,否则使用非public的接口所在的包
153 {
154 /*
155 * Choose a name for the proxy class to generate.
156 */
157 long num;
158 synchronized (nextUniqueNumberLock) {
159 num = nextUniqueNumber++;
160 }
161 上面代码为当前代理类计算独一无二的序号,然后在下面代码中组装出该来的全名如:com.sun.proxy.$Proxy0
String proxyName = proxyPkg + proxyClassNamePrefix + num;
162 /*
163 * Verify that the class loader hasn't already
164 * defined a class with the chosen name.
165 */
166 下面开始真正的创建工作
167 /*
168 * Generate the specified proxy class.
169 */
生成对应的字节码,java中,任何一个类都要有对应的字节码才能使用,因此这里也不例外
170 byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
171 proxyName, interfaces);
根据字节码创建真正的Class对象,也就是我们需要的代理类
172 try {
173 proxyClass = defineClass0(loader, proxyName,
174 proxyClassFile, 0, proxyClassFile.length);
175 } catch (ClassFormatError e) {
176 /*
177 * A ClassFormatError here means that (barring bugs in the
178 * proxy class generation code) there was some other
179 * invalid aspect of the arguments supplied to the proxy
180 * class creation (such as virtual machine limitations
181 * exceeded).
182 */
183 throw new IllegalArgumentException(e.toString());
184 }
185 }
186 // add to set of all generated proxy classes, for isProxyClass
加入已创建代理类集合,以备后面查找
187 proxyClasses.put(proxyClass, null);
188
189 } finally {
190 /*
191 * We must clean up the "pending generation" state of the proxy
192 * class cache entry somehow. If a proxy class was successfully
193 * generated, store it in the cache (with a weak reference);
194 * otherwise, remove the reserved entry. In all cases, notify
195 * all waiters on reserved entries in this cache.
196 */
这段代码放在finally中,可见非常重要,无论什么情况(代理类创建是否成功)都要执行,下面看看都做了什么
197 synchronized (cache) {
198 if (proxyClass != null) {
199 cache.put(key, new WeakReference<Class<?>>(proxyClass));
200 } else {
201 cache.remove(key);
202 }
如果代理类创建成功,则将缓存中对应项设置为正式的value值,否则,删除对应缓存项,如果不进行上述操作,则试想,另外一个线程查找时
获取到的代理类状态为“正在创建”,那么,则一直等待下去。
唤醒所有挂起在cache上的线程
203 cache.notifyAll();
204 }
205 }
返回创建的代理类
206 return proxyClass;