您的位置:首页 > 编程语言 > Java开发

Java中的动态代理以及Proxy类的偷瞄

2017-03-22 20:22 519 查看
动态代理机制

所谓动态代理,即通过代理类Proxy的代理,接口和实现类之间可以不直接发生联系,而可以在运行期(Runtime)实现动态关联。

Java动态代理类位于Java.lang.reflect包下,主要涉及到两个类。

(1)接口InvocationHandler:该接口中仅定义了一个方法。

Object invoke(Object obj, Method method, Object[] args);

在实际使用时,第一个参数obj一般指代理类,method是被代理的方法,args为该方法的参数数组。

(2)proxy:该类即为动态代理类,作用类实现了InvocationHandler接口的代理类,其中主要方法有:

protected Proxy(InvocationHandler h):构造方法,用于给内部的h赋值。

static Class getProxyClass(ClassLoader loader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。

static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用。

动态代理应用

Java 1.3中引入的动态代理类可以为已知接口的实现动态地创建包装器(wrapper)类。

与动态代理对应的是非动态代理,先来看看非动态代理的实现。

1. 定义接口和实现类并直接调用

接口的定义

1 package com.tuhooo.proxy.demo;
2
3 public interface Hello {
4
5     public void sayHello();
6
7 }

接口的实现类

1 package com.tuhooo.proxy.demo;
2
3 public class HelloEarth implements Hello {
4
5     @Override
6     public void sayHello() {
7         System.out.println("Hello earth!");
8     }
9
10 }

通过实现接口增强

1 package com.tuhooo.proxy.demo;
2
3 public class HelloEarthWrapper1 implements Hello {
4
5     private Hello helloImpl;
6
7     public HelloEarthWrapper1(Hello helloImpl) {
8         this.helloImpl = helloImpl;
9     }
10
11     @Override
12     public void sayHello() {
13         System.out.println("在sayHello之前执行了这条语句......");
14         helloImpl.sayHello();
15
16     }
17 }

通过继承对类进行增强

1 package com.tuhooo.proxy.demo;
2
3 public class HelloEarthWrapper2 extends HelloEarth {
4
5     private Hello helloImpl;
6
7     public HelloEarthWrapper2(Hello helloImpl) {
8         this.helloImpl = helloImpl;
9     }
10
11     @Override
12     public void sayHello() {
13         System.out.println("在sayHello之前执行了这条语句......");
14         helloImpl.sayHello();
15     }
16 }

实现InvocationHandler接口

1 package com.tuhooo.proxy.demo;
2
3 import java.lang.reflect.InvocationHandler;
4 import java.lang.reflect.Method;
5
6 public class HelloHandler implements InvocationHandler {
7
8     private Object proxyed; // 被代理的类
9
10     // 被代理的对象
11     public HelloHandler(Object obj) {
12
13         this.proxyed = obj;
14     }
15
16     @Override
17     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
18
19         Object result;
20         System.out.println("在sayHello()之前可以执行的语句");
21         // 调用原始对象的方法
22         result = method.invoke(this.proxyed, args);
23         System.out.println("在调用sayHello()之后");
24         return result;
25     }
26 }

测试代理类

1 package com.tuhooo.proxy.demo;
2
3 import java.lang.reflect.InvocationHandler;
4 import java.lang.reflect.Proxy;
5 import org.junit.Test;
6
7 public class TestProxy {
8
9     @Test
10     public void test1() {
11         Hello helloImpl = new HelloEarth();
12         Hello helloWrapper = new HelloEarthWrapper2(helloImpl);
13         helloWrapper.sayHello();
14     }
15
16     @Test
17     public void test2() {
18         // 被代理类的实例
19         Hello hello = new HelloEarth();
20         // InvocationHandler接口,传入被代理的类
21
22         InvocationHandler handler = new HelloHandler(hello);
23
24         // 生成代理类
25         // 1. 给我被代理类的类加载器加载被代理的类,为啥要类加载器呢
26         // 2. 给我被代理类的接口信息
27         // 3. 给我如何增强接口中的方法信息
28         Hello proxy = (Hello) Proxy.newProxyInstance(hello.getClass()
29         .getClassLoader(), hello.getClass().getInterfaces(), handler);
30         // 调用代理的方法
31         proxy.sayHello();
32     }
33 }


2. 使用包装类进行包装

包装类中有一个被包装的类的引用作为属性,和被包装类实现相同的接口,然后在实现接口的方法中调用和被包装类同名的接口中的方法实现方法的增强。这种解决方案的缺点就是当接口中的方法过多的时候就需要为接口中的每个方法都写一遍,即时不需要增强的方法也需要实现。

另一种做法是继承被包装的类,然后在包装类中重写需要增强的方法,但是缺点是只有在被包装类出现的地方才能使用被包装类,而实现接口的方法是在接口出现的地方都可以使用包装类。继承了被包装类之后的类,就是去了接口的好处,在包装类作为引用类型的地方必须的是被包装类及其子类,而不是接口出现。

3. 使用动态代理

使用动态代理则可以不需要实现接口中所有的方法,又可以获得接口的好处。动态代理要求要包装的对象必须实现一个接口,该接口定义了准备在包装器中使用的所有方法,这一限制是鼓励面向接口的编程,而不是限制编程,根据经验,每个类至少应该实现一个接口。良好的接口用法不仅使动态代理成为可能,还有利于程序的模块化。

创建动态代理类

调用动态代理类

主要的步骤有:

首先根据被代理对象创建一个代理类

创建动态代理对象的proxy1,第一个参数为被代理类的类加载器,第二个参数为该类的接口,第三个对象为代理对象的实例。

通过调用代理对象中增强的方法

上述过程就是告诉Proxy类用一个指定的类加载器来动态创建一个对象,该对象要实现指定的接口,并用提供的InvocationHandler来代替传统的方法主体。在实现InvocationHandler接口的类中invoke()方法中,完全不存在对Hello接口的引用,在上述的例子中,以构造方法的传参的形式,为InvocationHandler的实现类提供了被代理接口的实例。代理接口实例上的任何方法调用最终都由InvocationHandler的实例委托给代理接口实例,这是最常见的设计。但是,InvocationHandler实例不一定非要委托给被代理的接口的另一个实例。事实上,InvocationHandler可以自行提供方法主体,完全不必委托给被代理类来实现。如果被代理接口发生变化,InvocationHandler中的实例仍然是可用的。

动态代理可以实现许多AOP方面的功能:安全、事务、日志、过滤、编码、解码等功能,而且纯粹是热插拔的。AOP的好处是可以对类的实例统一实现拦截操作,通常应用在日志、权限、缓存、连接池中等。

基于动态代理的字节码库

了解动态代理的原理之后,我们完全可以自己实现这样一个动态代理,只要生成该类的class文件的内存映像即可。有很多这样的工具。

BCEL:

SERP:

ASM:Java字节码汇编语言。ASM是轻量级的Java字节码处理框架,可以动态生成二进制格式的stub类或其他代理类,或者在类被Java虚拟机装载之前动态修改类。ASM设计的目的就是在运行时使用,因此要尽量体积小速度快。

cglib:Code Generation Library的缩写,依赖与ASM库。Spring和Hibernate选择了同样的cglib包。Hibernate主要利用cglib生成pojo的子类并用override get方法来实现lazy loading机制,Spring则是利用cglib来实现动态代理。JDK的动态代理必须得实现接口才行。

使用CGLib进行动态代理

待增强的类

1 package com.tuhooo.cglib.demo;
2
3 public class HelloWorld{
4     public void savePerson() {
5         System.out.println("hello, world!");
6     }
7 }

增强类

1 package com.tuhooo.cglib.demo;
2
3 import java.lang.reflect.Method;
4 import net.sf.cglib.proxy.Enhancer;
5 import net.sf.cglib.proxy.MethodInterceptor;
6 import net.sf.cglib.proxy.MethodProxy;
7
8 public class HelloWorldInterceptor implements MethodInterceptor{
9
10     // 被增强的类
11     private Object target;
12     // 如何增强方法的信息
13     private Strength strength;
14
15     public HelloWorldInterceptor(Object target, Strength strength) {
16         super();
17         this.target = target;
18         this.strength = strength;
19     }
20
21     /**
22      * 用来产生代理对象
23      */
24     public Object createProxy(){
25         // 增强类
26         Enhancer enhancer = new Enhancer();
27         // 设置增强类的回调方法
28         enhancer.setCallback(this);
29         //设置代理类的父类
30         enhancer.setSuperclass(HelloWorld.class);
31         return enhancer.create();
32     }
33
34     // 这里相当于InvocationHandler接口中的invoke方法
35     public Object intercept(Object arg0, Method method, Object[] arg2,
36             MethodProxy arg3) throws Throwable {
37         this.strength.begin();
38         method.invoke(target, arg2);
39         this.strength.end();
40         return null;
41     }
42 }

增强的方法

1 package com.tuhooo.cglib.demo;
2
3 // 待增强的方法
4 public class Strength {
5     // 前增强
6     public void begin(){
7         System.out.println("begin......");
8     }
9     // 后增强
10     public void end(){
11         System.out.println("end.......");
12     }
13 }

测试增强

1 package com.tuhooo.cglib.demo;
2
3 import org.junit.Test;
4
5 /**
6  * 使用cglib产生的代理类,其代理类是目标类的子类
7  */
8 public class TestHello {
9     @Test
10     public void testPersonDaoProxy(){
11         Object target = new HelloWorld();
12         Strength strength = new Strength();
13         HelloWorldInterceptor interceptor = new HelloWorldInterceptor(target, strength);
14         HelloWorld helloWorldProxy = (HelloWorld)interceptor.createProxy();
15         helloWorldProxy.savePerson();
16     }
17 }


InvocationHandler源码

1 package java.lang.reflect;
2
3 /**
4  * 每个代理类实例都有一个与之关联的invocation句柄。
5  * 当代理类的实例调用一个方法的时候,
6  * 该方法的invocation被编码并且被分发到它对应的invocation句柄
7  */
8 public interface InvocationHandler {
9
10     public Object invoke(Object proxy, Method method, Object[] args)
11         throws Throwable;
12 }

Proxy的源码

1 package java.lang.reflect;
2
3 import java.lang.ref.Reference;
4 import java.lang.ref.WeakReference;
5 import java.security.AccessController;
6 import java.security.Permission;
7 import java.security.PrivilegedAction;
8 import java.util.Arrays;
9 import java.util.Collections;
10 import java.util.HashMap;
11 import java.util.HashSet;
12 import java.util.Map;
13 import java.util.Set;
14 import java.util.List;
15 import java.util.WeakHashMap;
16 import sun.misc.ProxyGenerator;
17 import sun.reflect.CallerSensitive;
18 import sun.reflect.Reflection;
19 import sun.reflect.misc.ReflectUtil;
20 import sun.security.util.SecurityConstants;
21
22 /**
23  * Proxy类提供了用于创建代理对象和实例的静态方法,
24    并且它也是所有通过这些静态方法创建出的代理类的父类。
25  *
26  * 从某个接口创建代理对象的方法如下:
27  *
28  * InvocationHandler handler = new MyInvocationHandler(...);
29  * Class proxyClass = Proxy.getProxyClass(
30  *     Foo.class.getClassLoader(), new Class[] { Foo.class });
31  * Foo f = (Foo) proxyClass.
32  *     getConstructor(new Class[] { InvocationHandler.class }).
33  *     newInstance(new Object[] { handler });
34  * 或者有更简单的方法
35  * Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
36  *                   new Class[] { Foo.class }, handler);
37  *
38  * 一个动态代理类(以下简称为代理类)是该类被创建时在运行时动态
39  * 实现一系列接口的类,有如下的特性。
40  *
41  * 动态代理接口是被动态类实现的接口。
42  * 代理实例是代理类一个一个实例。
43  *
44  * 每个代理实例都和一个实现了InvocationHandler接口的invocation handler对象关联。
45  * 通过代理接口进行的代理类实例的方法调用将会被分发给invocation handler实例,同时传递的
46  * 参数有代理实例,确定被调用方法的Method对象和Object数组类型的参数。
47  *
48  *
49  * containing the arguments.  The invocation handler processes the
50  * encoded method invocation as appropriate and the result that it
51  * returns will be returned as the result of the method invocation on
52  * the proxy instance.
53  *
54  * <p>A proxy class has the following properties:
55  *
56  * <ul>
57  * <li>Proxy classes are public, final, and not abstract.
58  *
59  * <li>The unqualified name of a proxy class is unspecified.  The space
60  * of class names that begin with the string {@code "$Proxy"}
61  * should be, however, reserved for proxy classes.
62  *
63  * <li>A proxy class extends {@code java.lang.reflect.Proxy}.
64  *
65  * <li>A proxy class implements exactly the interfaces specified at its
66  * creation, in the same order.
67  *
68  * <li>If a proxy class implements a non-public interface, then it will
69  * be defined in the same package as that interface.  Otherwise, the
70  * package of a proxy class is also unspecified.  Note that package
71  * sealing will not prevent a proxy class from being successfully defined
72  * in a particular package at runtime, and neither will classes already
73  * defined by the same class loader and the same package with particular
74  * signers.
75  *
76  * <li>Since a proxy class implements all of the interfaces specified at
77  * its creation, invoking {@code getInterfaces} on its
78  * {@code Class} object will return an array containing the same
79  * list of interfaces (in the order specified at its creation), invoking
80  * {@code getMethods} on its {@code Class} object will return
81  * an array of {@code Method} objects that include all of the
82  * methods in those interfaces, and invoking {@code getMethod} will
83  * find methods in the proxy interfaces as would be expected.
84  *
85  * <li>The {@link Proxy#isProxyClass Proxy.isProxyClass} method will
86  * return true if it is passed a proxy class-- a class returned by
87  * {@code Proxy.getProxyClass} or the class of an object returned by
88  * {@code Proxy.newProxyInstance}-- and false otherwise.
89  *
90  * <li>The {@code java.security.ProtectionDomain} of a proxy class
91  * is the same as that of system classes loaded by the bootstrap class
92  * loader, such as {@code java.lang.Object}, because the code for a
93  * proxy class is generated by trusted system code.  This protection
94  * domain will typically be granted
95  * {@code java.security.AllPermission}.
96  *
97  * <li>Each proxy class has one public constructor that takes one argument,
98  * an implementation of the interface {@link InvocationHandler}, to set
99  * the invocation handler for a proxy instance.  Rather than having to use
100  * the reflection API to access the public constructor, a proxy instance
101  * can be also be created by calling the {@link Proxy#newProxyInstance
102  * Proxy.newProxyInstance} method, which combines the actions of calling
103  * {@link Proxy#getProxyClass Proxy.getProxyClass} with invoking the
104  * constructor with an invocation handler.
105  * </ul>
106  *
107  * <p>A proxy instance has the following properties:
108  *
109  * <ul>
110  * <li>Given a proxy instance {@code proxy} and one of the
111  * interfaces implemented by its proxy class {@code Foo}, the
112  * following expression will return true:
113  * <pre>
114  *     {@code proxy instanceof Foo}
115  * </pre>
116  * and the following cast operation will succeed (rather than throwing
117  * a {@code ClassCastException}):
118  * <pre>
119  *     {@code (Foo) proxy}
120  * </pre>
121  *
122  * <li>Each proxy instance has an associated invocation handler, the one
123  * that was passed to its constructor.  The static
124  * {@link Proxy#getInvocationHandler Proxy.getInvocationHandler} method
125  * will return the invocation handler associated with the proxy instance
126  * passed as its argument.
127  *
128  * <li>An interface method invocation on a proxy instance will be
129  * encoded and dispatched to the invocation handler's {@link
130  * InvocationHandler#invoke invoke} method as described in the
131  * documentation for that method.
132  *
133  * <li>An invocation of the {@code hashCode},
134  * {@code equals}, or {@code toString} methods declared in
135  * {@code java.lang.Object} on a proxy instance will be encoded and
136  * dispatched to the invocation handler's {@code invoke} method in
137  * the same manner as interface method invocations are encoded and
138  * dispatched, as described above.  The declaring class of the
139  * {@code Method} object passed to {@code invoke} will be
140  * {@code java.lang.Object}.  Other public methods of a proxy
141  * instance inherited from {@code java.lang.Object} are not
142  * overridden by a proxy class, so invocations of those methods behave
143  * like they do for instances of {@code java.lang.Object}.
144  * </ul>
145  *
146  * <h3>Methods Duplicated in Multiple Proxy Interfaces</h3>
147  *
148  * <p>When two or more interfaces of a proxy class contain a method with
149  * the same name and parameter signature, the order of the proxy class's
150  * interfaces becomes significant.  When such a <i>duplicate method</i>
151  * is invoked on a proxy instance, the {@code Method} object passed
152  * to the invocation handler will not necessarily be the one whose
153  * declaring class is assignable from the reference type of the interface
154  * that the proxy's method was invoked through.  This limitation exists
155  * because the corresponding method implementation in the generated proxy
156  * class cannot determine which interface it was invoked through.
157  * Therefore, when a duplicate method is invoked on a proxy instance,
158  * the {@code Method} object for the method in the foremost interface
159  * that contains the method (either directly or inherited through a
160  * superinterface) in the proxy class's list of interfaces is passed to
161  * the invocation handler's {@code invoke} method, regardless of the
162  * reference type through which the method invocation occurred.
163  *
164  * <p>If a proxy interface contains a method with the same name and
165  * parameter signature as the {@code hashCode}, {@code equals},
166  * or {@code toString} methods of {@code java.lang.Object},
167  * when such a method is invoked on a proxy instance, the
168  * {@code Method} object passed to the invocation handler will have
169  * {@code java.lang.Object} as its declaring class.  In other words,
170  * the public, non-final methods of {@code java.lang.Object}
171  * logically precede all of the proxy interfaces for the determination of
172  * which {@code Method} object to pass to the invocation handler.
173  *
174  * <p>Note also that when a duplicate method is dispatched to an
175  * invocation handler, the {@code invoke} method may only throw
176  * checked exception types that are assignable to one of the exception
177  * types in the {@code throws} clause of the method in <i>all</i> of
178  * the proxy interfaces that it can be invoked through.  If the
179  * {@code invoke} method throws a checked exception that is not
180  * assignable to any of the exception types declared by the method in one
181  * of the proxy interfaces that it can be invoked through, then an
182  * unchecked {@code UndeclaredThrowableException} will be thrown by
183  * the invocation on the proxy instance.  This restriction means that not
184  * all of the exception types returned by invoking
185  * {@code getExceptionTypes} on the {@code Method} object
186  * passed to the {@code invoke} method can necessarily be thrown
187  * successfully by the {@code invoke} method.
188  *
189  * @author      Peter Jones
190  * @see         InvocationHandler
191  * @since       1.3
192  */
193
194 // 代理对象是可以序列化的
195 public class Proxy implements java.io.Serializable {
196
197     private static final long serialVersionUID = -2222568056686623797L;
198
199     /** 为所有代理类的类名添加前缀,难怪hibernate中很多类都有$Proxy */
200     private final static String proxyClassNamePrefix = "$Proxy";
201
202     /** 代理类构造方法的参数类型 */
203     private final static Class[] constructorParams =
204         { InvocationHandler.class };
205
206     /** 将代理类的类加载器放在Proxy的maps结构中缓存起来 */
207     /** 为啥这里用了WeakHashMap() */
208     private static Map<ClassLoader, Map<List<String>, Object>> loaderToCache
209         = new WeakHashMap<>();
210
211     /** 用于标记正在生成的代理类 */
212     private static Object pendingGenerationMarker = new Object();
213
214     /** 下一个用于生成唯一代理类名字的数字 */
215     private static long nextUniqueNumber = 0;
216     private static Object nextUniqueNumberLock = new Object();
217
218     /** 所有代理类的集合,用于isProxyClass方法的实现 */
219     private static Map<Class<?>, Void> proxyClasses =
220         Collections.synchronizedMap(new WeakHashMap<Class<?>, Void>());
221
222     /**
223      * 代理实例的invocationHandler对象,原来放在这儿啊.
224      * @serial
225      */
226     protected InvocationHandler h;
227
228     /**
229      * 禁止实例化
230      */
231     private Proxy() {
232     }
233
234     /**
235      * 从一个子类中创建代理类的实例(最典型的是一个动态代理类)
236      * 构造方法的参数是用来指定invocation handler
237      * 这个方法还是受保护的呢
238      */
239     protected Proxy(InvocationHandler h) {
240         doNewInstanceCheck();
241         this.h = h;
242     }
243
244     /**
245      * 为什么不注释这个方法?
246      * 类名大致意思是代理访问助手?
247      * 这还是个静态的内部类
248      */
249     private static class ProxyAccessHelper {
250         // The permission is implementation specific.
251         // 权限是指定实现的。
252         static final Permission PROXY_PERMISSION =
253             new ReflectPermission("proxyConstructorNewInstance");
254         // These system properties are defined to provide a short-term
255         // workaround if customers need to disable the new security checks.
256         // 这些系统配置被定义用来提供短期的配置,如果用户需要禁止新的安全检查。
257         static final boolean allowNewInstance;
258         static final boolean allowNullLoader;
259         static {
260             allowNewInstance = getBooleanProperty("sun.reflect.proxy.allowsNewInstance");
261             allowNullLoader = getBooleanProperty("sun.reflect.proxy.allowsNullLoader");
262         }
263
264         // 方法参数还可以这样修饰final?
265         private static boolean getBooleanProperty(final String key) {
266             String s = AccessController.doPrivileged(new PrivilegedAction<String>() {
267                 public String run() {
268                     return System.getProperty(key);
269                 }
270             });
271             return Boolean.valueOf(s);
272         }
273
274         // 需要进行创建新实例的检查么
275         static boolean needsNewInstanceCheck(Class<?> proxyClass) {
276             if (!Proxy.isProxyClass(proxyClass) || allowNewInstance) {
277                 return false;
278             }
279
280             if (ReflectUtil.isNonPublicProxyClass(proxyClass)) {
281                 for (Class<?> intf : proxyClass.getInterfaces()) {
282                     if (!Modifier.isPublic(intf.getModifiers())) {
283                         return true;
284                     }
285                 }
286             }
287             return false;
288         }
289     }
290
291     /*
292      * Access check on a proxy class that implements any non-public interface.
293      *
294      * @throws  SecurityException if a security manager exists, and
295      *          the caller does not have the permission.
296      */
297     private void doNewInstanceCheck() {
298         SecurityManager sm = System.getSecurityManager();
299         Class<?> proxyClass = this.getClass();
300         if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(proxyClass)) {
301             try {
302                 sm.checkPermission(ProxyAccessHelper.PROXY_PERMISSION);
303             } catch (SecurityException e) {
304                 throw new SecurityException("Not allowed to construct a Proxy "
305                         + "instance that implements a non-public interface", e);
306             }
307         }
308     }
309
310     /**
311      * 这个方法是重头了
312      * 从给定的类加载器和接口数组返回动态代理类的Class对象。
313      * Returns the {@code java.lang.Class} object for a proxy class
314      * given a class loader and an array of interfaces.
315      * 代理将会通过指定的类加载器所定义而且将会实现所提供的所有的接口。
316      *
317      * 如果已经有实现了相同接口的代理类存在,那么将会直接放回已经存在的代理类;
318      * 否则,将会动态地创建和由类加载器定义的代理类被返回。
319
320      * 对于传递给Proxy.getProxyClass方法的参数有若干限制。
321      *
322      * 在数组中所有的类类型必须是接口,不是其他的类类型或者原始类型。
323      * 接口数组中的接口必须两两不同
324      * 所有的接口类型都可以通过指定的类加载器按名字进行加载。
325      * 也就是对于数组中的每个接口i如下判断必须为true
326      *     Class.forName(i.getName(), false, cl) == i
327      *
328      * 所有非公开的接口都必须在相同的包里面;不然的话,代理类不可能实现所有的接口,
329      * 不论它是在哪个包里面定义的。
330      *
331      * 对于指定接口的成员方法的集合的中的方法必须有相同的签名。
332      *
333      * 如果任何方法的返回类型是原始类型或者为空,那么所有的的方法都必须有相同的返回类型。
334      *
335      * 不然,其中一个方法必须可以对其他方法的返回类型是可赋值的。
336      *
337      * 生成的代理类不能超过虚拟机对其中的类的限制。例如,虚拟机会限制一个类的接口个数不超过65535;
338      * 因此传进去的接口的数组的长度不能超过65535
339      *
340      * 如果以上约束有违反的话,将会抛出IllegalArgumentException异常。
341      * 如果有接口是null的话,就会报NullPointerException异常。
342      *
343      * 注意到特定的代理接口的顺序是有意义的:对于创建具有相同代理接口的不同顺序的请求生成的代理类是不同的两个
344      * 代理类。(卧槽,这个也有影响,不读下源码一脸懵逼)
345      */
346     @CallerSensitive
347     public static Class<?> getProxyClass(ClassLoader loader,
348                                          Class<?>... interfaces)
349         throws IllegalArgumentException
350     {
351         // 安全管理
352         SecurityManager sm = System.getSecurityManager();
353         if (sm != null) {
354             checkProxyAccess(Reflection.getCallerClass(), loader, interfaces);
355         }
356
357         // 返回代理对象
358         return getProxyClass0(loader, interfaces);
359     }
360
361     /*
362      * Check permissions required to create a Proxy class.
363      *
364      * To define a proxy class, it performs the access checks as in
365      * Class.forName (VM will invoke ClassLoader.checkPackageAccess):
366      * 1. "getClassLoader" permission check if loader == null
367      * 2. checkPackageAccess on the interfaces it implements
368      *
369      * To get a constructor and new instance of a proxy class, it performs
370      * the package access check on the interfaces it implements
371      * as in Class.getConstructor.
372      *
373      * If an interface is non-public, the proxy class must be defined by
374      * the defining loader of the interface.  If the caller's class loader
375      * is not the same as the defining loader of the interface, the VM
376      * will throw IllegalAccessError when the generated proxy class is
377      * being defined via the defineClass0 method.
378      */
379     private static void checkProxyAccess(Class<?> caller,
380                                          ClassLoader loader,
381                                          Class<?>... interfaces)
382     {
383         SecurityManager sm = System.getSecurityManager();
384         if (sm != null) {
385             ClassLoader ccl = caller.getClassLoader();
386             if (loader == null && ccl != null) {
387                 if (!ProxyAccessHelper.allowNullLoader) {
388                     sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
389                 }
390             }
391             ReflectUtil.checkProxyPackageAccess(ccl, interfaces);
392         }
393     }
394
395     /**
396      * Generate a proxy class.  Must call the checkProxyAccess method
397      * to perform permission checks before calling this.
398      */
399     private static Class<?> getProxyClass0(ClassLoader loader,
400                                            Class<?>... interfaces) {
401
402         // 判断接口的个数
403         if (interfaces.length > 65535) {
404             throw new IllegalArgumentException("interface limit exceeded");
405         }
406
407         // 代理类
408         Class<?> proxyClass = null;
409
410         /* 接口名称的集合用来作为代理类的缓存 */
411         String[] interfaceNames = new String[interfaces.length];
412
413         // 检查接口是否有重复的
414         Set<Class<?>> interfaceSet = new HashSet<>();
415
416         for (int i = 0; i < interfaces.length; i++) {
417             /*
418              * 验证类加载器对接口名称的解析是同一个对象
419              * 因为不同类加载加载的类是不同的
420              */
421
422             // 获取接口的名字
423             String interfaceName = interfaces[i].getName();
424             Class<?> interfaceClass = null;
425             try {
426                 // 拿到接口的类类型
427                 interfaceClass = Class.forName(interfaceName, false, loader);
428             } catch (ClassNotFoundException e) {
429             }
430
431             // 两个类类型之间的比较
432             if (interfaceClass != interfaces[i]) {
433                 throw new IllegalArgumentException(
434                     interfaces[i] + " is not visible from class loader");
435             }
436
437             /*
438              * Verify that the Class object actually represents an
439              * interface.
440              */
441             if (!interfaceClass.isInterface()) {
442                 throw new IllegalArgumentException(
443                     interfaceClass.getName() + " is not an interface");
444             }
445
446             /*
447              * Verify that this interface is not a duplicate.
448              */
449             if (interfaceSet.contains(interfaceClass)) {
450                 throw new IllegalArgumentException(
451                     "repeated interface: " + interfaceClass.getName());
452             }
453
454             // 将接口加入到集合中
455             interfaceSet.add(interfaceClass);
456
457             interfaceNames[i] = interfaceName;
458         }
459
460         /*
461          * 使用字符串代表代理接口作为代理类缓存的主键(而不是它们的类对象)
462          * 已经足够了因为我们要求代理接口必须能根据给定的类加载器通过名字被解析,
463          * 而且还有一个好处是,使用字符串代表类弥补了对类的隐式弱引用。
464          */
465
466         // 将数组转为字符串
467         List<String> key = Arrays.asList(interfaceNames);
468
469         /*
470          * 根据类加载器找到或者创建代理类的缓存.
471          */
472         Map<List<String>, Object> cache;
473         synchronized (loaderToCache) {
474             cache = loaderToCache.get(loader);
475             if (cache == null) {
476                 cache = new HashMap<>();
477                 loaderToCache.put(loader, cache);
478             }
479             /*
480              * 这个映射在这个方法执行时一直有效,不用过多的同步,
481              * 因为仅仅会在类加载器不可达的时候被移除。
482              */
483         }
484
485         /*
486          * Look up the list of interfaces in the proxy class cache using
487          * the key.  This lookup will result in one of three possible
488          * kinds of values:
489          *     null, if there is currently no proxy class for the list of
490          *         interfaces in the class loader,
491          *     the pendingGenerationMarker object, if a proxy class for the
492          *         list of interfaces is currently being generated,
493          *     or a weak reference to a Class object, if a proxy class for
494          *         the list of interfaces has already been generated.
495          */
496         synchronized (cache) {
497             /*
498              * Note that we need not worry about reaping the cache for
499              * entries with cleared weak references because if a proxy class
500              * has been garbage collected, its class loader will have been
501              * garbage collected as well, so the entire cache will be reaped
502              * from the loaderToCache map.
503              */
504             do {
505                 Object value = cache.get(key);
506                 if (value instanceof Reference) {
507                     proxyClass = (Class<?>) ((Reference) value).get();
508                 }
509                 if (proxyClass != null) {
510                     // proxy class already generated: return it
511                     return proxyClass;
512                 } else if (value == pendingGenerationMarker) {
513                     // proxy class being generated: wait for it
514                     try {
515                         cache.wait();
516                     } catch (InterruptedException e) {
517                         /*
518                          * The class generation that we are waiting for should
519                          * take a small, bounded time, so we can safely ignore
520                          * thread interrupts here.
521                          */
522                     }
523                     continue;
524                 } else {
525                     /*
526                      * No proxy class for this list of interfaces has been
527                      * generated or is being generated, so we will go and
528                      * generate it now.  Mark it as pending generation.
529                      */
530                     cache.put(key, pendingGenerationMarker);
531                     break;
532                 }
533             } while (true);
534         }
535
536         try {
537             String proxyPkg = null;     // package to define proxy class in
538
539             /*
540              * Record the package of a non-public proxy interface so that the
541              * proxy class will be defined in the same package.  Verify that
542              * all non-public proxy interfaces are in the same package.
543              */
544             for (int i = 0; i < interfaces.length; i++) {
545                 int flags = interfaces[i].getModifiers();
546                 if (!Modifier.isPublic(flags)) {
547                     String name = interfaces[i].getName();
548                     int n = name.lastIndexOf('.');
549                     String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
550                     if (proxyPkg == null) {
551                         proxyPkg = pkg;
552                     } else if (!pkg.equals(proxyPkg)) {
553                         throw new IllegalArgumentException(
554                             "non-public interfaces from different packages");
555                     }
556                 }
557             }
558
559             if (proxyPkg == null) {
560                 // if no non-public proxy interfaces, use com.sun.proxy package
561                 proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
562             }
563
564             {
565                 /*
566                  * Choose a name for the proxy class to generate.
567                  */
568                 long num;
569                 synchronized (nextUniqueNumberLock) {
570                     num = nextUniqueNumber++;
571                 }
572                 String proxyName = proxyPkg + proxyClassNamePrefix + num;
573                 /*
574                  * Verify that the class loader hasn't already
575                  * defined a class with the chosen name.
576                  */
577
578                 /*
579                  * 生成指定的代理类,可以看出这里的是二进制类型
580                  * ProxyGenerator的源码看不到了
581                  */
582                 byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
583                     proxyName, interfaces);
584                 try {
585                     // defineClass0是一个本地方法
586                     proxyClass = defineClass0(loader, proxyName,
587                         proxyClassFile, 0, proxyClassFile.length);
588                 } catch (ClassFormatError e) {
589                     /*
590                      * A ClassFormatError here means that (barring bugs in the
591                      * proxy class generation code) there was some other
592                      * invalid aspect of the arguments supplied to the proxy
593                      * class creation (such as virtual machine limitations
594                      * exceeded).
595                      */
596                     throw new IllegalArgumentException(e.toString());
597                 }
598             }
599             // 将其加入到所有生成的代理类的集合中,用于判断是否是代理类.
600             proxyClasses.put(proxyClass, null);
601
602         } finally {
603             /*
604              * We must clean up the "pending generation" state of the proxy
605              * class cache entry somehow.  If a proxy class was successfully
606              * generated, store it in the cache (with a weak reference);
607              * otherwise, remove the reserved entry.  In all cases, notify
608              * all waiters on reserved entries in this cache.
609              */
610             synchronized (cache) {
611                 if (proxyClass != null) {
612                     cache.put(key, new WeakReference<Class<?>>(proxyClass));
613                 } else {
614                     cache.remove(key);
615                 }
616                 cache.notifyAll();
617             }
618         }
619
620         // 返回代理类
621         return proxyClass;
622     }
623
624     @CallerSensitive
625     public static Object newProxyInstance(ClassLoader loader,
626                                           Class<?>[] interfaces,
627                                           InvocationHandler h)
628         throws IllegalArgumentException
629     {
630         if (h == null) {
631             throw new NullPointerException();
632         }
633
634         // 安全检查
635         final SecurityManager sm = System.getSecurityManager();
636         if (sm != null) {
637             checkProxyAccess(Reflection.getCallerClass(), loader, interfaces);
638         }
639
640         /*
641          * 查找或者生成指定的代理类
642          */
643         Class<?> cl = getProxyClass0(loader, interfaces);
644
645         /*
646          * 调用指定了invocation handler的构造方法。
647          */
648         try {
649             final Constructor<?> cons = cl.getConstructor(constructorParams);
650             final InvocationHandler ih = h;
651             if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
652                 // create proxy instance with doPrivilege as the proxy class may
653                 // implement non-public interfaces that requires a special permission
654                 return AccessController.doPrivileged(new PrivilegedAction<Object>() {
655                     public Object run() {
656                         return newInstance(cons, ih);
657                     }
658                 });
659             } else {
660                 // 直接返回了代理对象
661                 return newInstance(cons, ih);
662             }
663         } catch (NoSuchMethodException e) {
664             throw new InternalError(e.toString());
665         }
666     }
667
668     private static Object newInstance(Constructor<?> cons, InvocationHandler h) {
669         try {
670             return cons.newInstance(new Object[] {h} );
671         } catch (IllegalAccessException | InstantiationException e) {
672             throw new InternalError(e.toString());
673         } catch (InvocationTargetException e) {
674             Throwable t = e.getCause();
675             if (t instanceof RuntimeException) {
676                 throw (RuntimeException) t;
677             } else {
678                 throw new InternalError(t.toString());
679             }
680         }
681     }
682
683     /**
684      * Returns true if and only if the specified class was dynamically
685      * generated to be a proxy class using the {@code getProxyClass}
686      * method or the {@code newProxyInstance} method.
687      *
688      * <p>The reliability of this method is important for the ability
689      * to use it to make security decisions, so its implementation should
690      * not just test if the class in question extends {@code Proxy}.
691      *
692      * @param   cl the class to test
693      * @return  {@code true} if the class is a proxy class and
694      *          {@code false} otherwise
695      * @throws  NullPointerException if {@code cl} is {@code null}
696      */
697     public static boolean isProxyClass(Class<?> cl) {
698         if (cl == null) {
699             throw new NullPointerException();
700         }
701
702         return proxyClasses.containsKey(cl);
703     }
704
705     /**
706      * Returns the invocation handler for the specified proxy instance.
707      *
708      * @param   proxy the proxy instance to return the invocation handler for
709      * @return  the invocation handler for the proxy instance
710      * @throws  IllegalArgumentException if the argument is not a
711      *          proxy instance
712      */
713     @CallerSensitive
714     public static InvocationHandler getInvocationHandler(Object proxy)
715         throws IllegalArgumentException
716     {
717         /*
718          * Verify that the object is actually a proxy instance.
719          */
720         if (!isProxyClass(proxy.getClass())) {
721             throw new IllegalArgumentException("not a proxy instance");
722         }
723
724         final Proxy p = (Proxy) proxy;
725         final InvocationHandler ih = p.h;
726         if (System.getSecurityManager() != null) {
727             Class<?> ihClass = ih.getClass();
728             Class<?> caller = Reflection.getCallerClass();
729             if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(),
730                                                     ihClass.getClassLoader()))
731             {
732                 ReflectUtil.checkPackageAccess(ihClass);
733             }
734         }
735
736         return ih;
737     }
738
739     private static native Class defineClass0(ClassLoader loader, String name,
740                                              byte[] b, int off, int len);
741 }

总结Proxy:



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: