java.lang.Object java.lang.reflect.Proxy
public class Proxy
Proxy
提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。
创建某一接口 Foo
的代理:
InvocationHandler handler = new MyInvocationHandler(...); Class proxyClass = Proxy.getProxyClass( Foo.class.getClassLoader(), new Class[] { Foo.class }); Foo f = (Foo) proxyClass. getConstructor(new Class[] { InvocationHandler.class }). newInstance(new Object[] { handler });或使用以下更简单的方法:
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class[] { Foo.class }, handler);
动态代理类(以下简称为代理类)是一个实现在创建类时在运行时指定的接口列表的类,该类具有下面描述的行为。 代理接口 是代理类实现的一个接口。 代理实例 是代理类的一个实例。 每个代理实例都有一个关联的调用处理程序 对象,它可以实现接口 InvocationHandler
。通过其中一个代理接口的代理实例上的方法调用将被指派到实例的调用处理程序的 Invoke
方法,并传递代理实例、识别调用方法的 java.lang.reflect.Method
对象以及包含参数的 Object
类型的数组。调用处理程序以适当的方式处理编码的方法调用,并且它返回的结果将作为代理实例上方法调用的结果返回。
代理类具用以下属性:
"$Proxy"
开头的类名空间应该为代理类保留。 java.lang.reflect.Proxy
。 Class
对象调用 getInterfaces
将返回一个包含相同接口列表的数组(按其创建时指定的顺序),对其 Class
对象调用 getMethods
将返回一个包括这些接口中所有方法的 Method
对象的数组,并且调用 getMethod
将会在代理接口中找到期望的一些方法。 Proxy.isProxyClass
方法传递代理类(由 Proxy.getProxyClass
返回的类,或由 Proxy.newProxyInstance
返回的对象的类),则该方法返回 true,否则返回 false。 java.security.ProtectionDomain
与由引导类加载器(如 java.lang.Object
)加载的系统类相同,原因是代理类的代码由受信任的系统代码生成。此保护域通常被授予 java.security.AllPermission
。 InvocationHandler
的实现)的公共构造方法,用于设置代理实例的调用处理程序。并非必须使用反射 API 才能访问公共构造方法,通过调用 Proxy.newInstance
方法(将调用 Proxy.getProxyClass
的操作和调用带有调用处理程序的构造方法结合在一起)也可以创建代理实例。 代理实例具有以下属性:
proxy
和一个由其代理类 Foo
实现的接口,以下表达式将返回 true:
proxy instanceof Foo
并且以下的强制转换操作将会成功(而不抛出 ClassCastException
):
(Foo) proxy
Proxy.getInvocationHandler
方法将返回与作为其参数传递的代理实例相关的调用处理程序。 Invoke
方法。 java.lang.Object
中声明的 hashCode
、equals
或 toString
方法的调用将按照与编码和指派接口方法调用相同的方式进行编码,并被指派到调用处理程序的 invoke
方法,如上所述。传递到 invoke
的 Method
对象的声明类是 java.lang.Object
。代理类不重写从 java.lang.Object
继承的代理实例的其他公共方法,所以这些方法的调用行为与其对 java.lang.Object
实例的操作一样。 当代理类的两个或多个接口包含一个具有相同名称和参数签名的方法时,代理类的接口顺序变得非常重要。在代理实例上调用重复方法 时,传递到调用处理程序的 Method
对象没有必要成为其声明类可以从接口(通过该接口调用代理方法)的引用类型指派的对象。此限制存在的原因是,生成的代理类中的相应方法实现无法确定它通过哪一个接口调用。因此,在代理实例上调用重复方法时,第一个接口中的方法的 Method
对象包含接口的代理类列表中的方法(直接或通过超级接口继承),该对象会传递到调用处理程序的 invoke
方法,无论该方法调用通过哪一种引用类型发生。
如果代理接口包含某一方法,它的名称和参数签名与 java.lang.Object
的 hashCode
、equals
或 toString
方法相同,那么在代理实例上调用这样的方法时,传递到调用处理程序的 Method
对象将使 java.lang.Object
成为其声明类。换句话说,java.lang.Object
公共的非最终方法理论上在所有代理接口之前,以便确定哪一个 Method
对象传递到调用处理程序。
还要注意,当重复方法被指派到调用处理程序时,invoke
方法只可以抛出经过检查的异常类型,该异常类型可以使用所有 代理接口(可以通过它调用)中方法的 throws
子句指派一种异常类型。如果 invoke
方法抛出一个经过检查的异常,该异常没有指派给任何由一个代理接口(可以通过它调用)中的方法声明的异常类型,那么该代理实例上的调用将抛出一个未经检查的 UndeclaredThrowableException
。此限制表示并非所有的由传递到 invoke
方法的 Method
对象上调用 getExceptionTypes
返回的异常类型都可以由 invoke
方法成功抛出。
InvocationHandler
,
序列化表格
字段摘要 | |
---|---|
protected InvocationHandler |
h 此代理实例的调用处理程序。 |
构造方法摘要 | |
---|---|
protected |
Proxy(InvocationHandler h) 使用其调用处理程序的指定值从子类(通常为动态代理类)构建新的 Proxy 实例。 |
方法摘要 | |
---|---|
static InvocationHandler |
getInvocationHandler(Object proxy) 返回指定代理实例的调用处理程序。 |
static Class<?> |
getProxyClass(ClassLoader loader, Class<?>... interfaces) 返回代理类的 java.lang.Class 对象,并向其提供类加载器和接口数组。 |
static boolean |
isProxyClass(Class<?> cl) 当且仅当指定的类通过 getProxyClass 方法或 newProxyInstance 方法动态生成为代理类时,返回 true。 |
static Object |
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。 |
从类 java.lang.Object 继承的方法 |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
字段详细信息 |
---|
protected InvocationHandler h
构造方法详细信息 |
---|
protected Proxy(InvocationHandler h)
Proxy
实例。
h
- 此代理实例的调用处理程序
方法详细信息 |
---|
public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException
java.lang.Class
对象,并向其提供类加载器和接口数组。该代理类将由指定的类加载器定义,并将实现提供的所有接口。如果类加载器已经定义了具有相同排列接口的代理类,那么现有的代理类将被返回;否则,类加载器将动态生成并定义这些接口的代理类。
对可以传递给 Proxy.getProxyClass
的参数有以下几个限制:
interfaces
数组中的所有 Class
对象必须表示接口,而不能表示类或基本类型。 interfaces
数组中的两个元素不能引用同一 Class
对象。 cl
和所有接口 i
,以下表达式必须为 true: Class.forName(i.getName(), false, cl) == i
interfaces
数组的大小必须不超过 65535。 如果违反了这些限制,Proxy.getProxyClass
将抛出 IllegalArgumentException
。如果 interfaces
数组参数或其任何元素为 null
,则将抛出 NullPointerException
。
注意,指定的代理接口的顺序非常重要:对接口组合相同但顺序不同的代理类的两个请求会导致两个不同的代理类。
loader
- 定义代理类的类加载器
interfaces
- 代理类要实现的接口列表
IllegalArgumentException
- 如果违反传递到
getProxyClass
的参数上的任何限制
NullPointerException
- 如果
interfaces
数组参数或其任何元素为
null
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
Proxy.getProxyClass(loader, interfaces). getConstructor(new Class[] { InvocationHandler.class }). newInstance(new Object[] { handler });
Proxy.newProxyInstance
抛出 IllegalArgumentException
,原因与 Proxy.getProxyClass
相同。
loader
- 定义代理类的类加载器
interfaces
- 代理类要实现的接口列表
h
- 指派方法调用的调用处理程序
IllegalArgumentException
- 如果违反传递到
getProxyClass
的参数上的任何限制
NullPointerException
- 如果
interfaces
数组参数或其任何元素为
null
,或如果调用处理程序
h
为
null
public static boolean isProxyClass(Class<?> cl)
getProxyClass
方法或
newProxyInstance
方法动态生成为代理类时,返回 true。
此方法的可靠性对于使用它做出安全决策而言非常重要,所以此方法的实现不应仅测试相关的类是否可以扩展 Proxy
。
cl
- 要测试的类
true
,否则为
false
NullPointerException
- 如果
cl
为
null
public static InvocationHandler getInvocationHandler(Object proxy) throws IllegalArgumentException
proxy
- 返回调用处理程序的代理实例
IllegalArgumentException
- 如果参数不是一个代理实例