动态代理类描述
动态代理类(以下简称为代理类)是一个实现在创建类时在运行时指定的接口列表的类,该类具有下面描述的行为。 代理接口 是代理类实现的一个接口。 代理实例 是代理类的一个实例。 每个代理实例都有一个关联的调用处理程序 对象,它可以实现接口
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 的操作和调用带有调用处理程序的构造方法结合在一起)也可以创建代理实例。
代理实例具有以下属性:
1、
proxy instanceof Foo 返回true, 并且可强转
(Foo) proxy
2、每个代理的实例的处理器InvocationHandler h 引用可以通过
Proxy.getInvocationHandler(
Object
proxy) 方式来获取
3、
代理实例上的接口方法调用将按照该方法的文档描述进行编码,并被指派到调用处理程序的
Invoke
方法。
4、代理类不重写Object的方法
在多代理接口中重复的方法
接口中的顺序需要值得注意的,第一个接口的中方法的Method会被指派到invoke 方法,所以如果第一个方法的接口不是handle.invoke中需要处理的对象的接口则可能会报异常: java.lang.IllegalArgumentException: object is not an instance of declaring class
如: 接口Subject和 SubjuectDuplicate 定义了重复的方法 public void rent() 和 public void hello(String str);而RealSubject 只实现了Subject接口:
public class RealSubject implements Subject
{
@Override
public void rent() { System.out.println("I want to rent my house");}
@Override
public void hello(String str) { System.out.println("hello: " + str); }
}
调用:
// 我们要代理的真实对象
Subject realSubject = new RealSubject();
// 我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
InvocationHandler handler = new DynamicProxy(realSubject);
// Class>[] interfaces={Subject.class,SubjuectDuplicate.class}; //ok
Class>[] interfaces={SubjuectDuplicate.class,Subject.class}; //报异常:Exception in thread "main" java.lang.IllegalArgumentException: object is not an instance of declaring class
Subject subject = (Subject)Proxy.newProxyInstance(
handler.getClass().getClassLoader(),
interfaces,
handler);
subject.rent();
//在调用时出现异常
subject.hello("world");
InvocationHandler 的invoke参数一点说明
invoke(Object proxy, Method method, Object[] params) 中好多实现类中proxy参数不使用....
如.:mybatis中的 PreparedStatementLogger、ResultSetLogger、StatementLogger等