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

初探java的Proxy+InvocationHandler

2014-04-22 00:00 239 查看
java.lang.reflect.InvocationHandler
一个由代理实例的调用处理程序实现的接口。
每个代理实例有一个关联的调用处理程序。
当调用代理实例上的一个方法,该方法的调用将被编码并转发到它所关联的调用处理程序的方法。

public Object invoke(Object proxy, Method method, Object[] args)throws Throwable
处理代理实例上一个方法的调用并返回处理结果。
当一个代理实例上的一个方法被调用时,则其关联的调用处理程序这个方法将被调用。

proxy:被调用方法的代理实例
method:与代理实例上调用的接口方法对应的方法对象,该方法对象将是接口中声明的方法,也可以是代理类通过代理接口的父接口继承的方法
args:包含代理实例上方法调用被传递的参数值对象数组,如接口方法没有参数则为null,原始类型的参数用适当的原始包装类的实例 如java.lang.Integer 等
return:从代理实例上方法调用返回的值。如果接口方法声明的返回类型是原始类型,则返回与之相应的原始包装类的实例,否则 返回其声明指定的类型。
若返回值为null并且接口的方法是返回类似是原始类型,则抛出NullPointerException。
若返回值与接口方法声明的返回类型不兼容,则抛出ClassCastException
throws:从代理实例上方法调用抛出的异常。异常类型是接口方法可抛出的任何异常类型or未受检查异常or错误
若抛出一个受检查异常而该受检查不是接口方法中声明的异常类型,则一个UndeclaredThrowableException抛出

java.lang.reflect.Proxy

提供创建动态代理类和实例的static 方法,并且通过这些方法创建所有动态代理类的父类。
创建一些接口的代理:
InvocationHandler handler = new MyInvocationHandler(...);
Class proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(),Foo.class);
Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).newInstance(handler);

或更简单:
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class[]{Foo.class}, handler);

一个动态代理类(代理类)是一类,当该类创建后在运行时指定实现接口列表与行为,描述如下:
一个代理接口是一个由代理类实现的接口
一个代理实例是一个代理类的实例对象
每一个代理实例有一个关联的调用处理程序对象,该调用处理程序对象实现InvocationHandler接口。
一个代理类由下面属性:
如果所有的代理接口是public,代理类是public,final,和 非abstract的
如果所有的代理接口是 non-public,代理类是non-public,final和非abstract的
未限定名称的代理类是未指定的。类名的空间从字符串"$Proxy"开始的提供,应该保留为代理类
一个继承java.lang.reflect.Proxy的代理类
一个代理类实现完全在其指定的接口上创建,在同一顺序
若一个代理类实现一个non-public接口,则它将定义在和该non-public接口相同的包。否则,这个代理类的包也是未指定。
注意:包的封闭不能防止来自运行时一个特定包中已有成功定义的一个代理类(相同class loader已经定义的类和特定签名的相同包)

代理类在它创建时实现所有指定的接口,调用getInterfaces方法将返回包含相同接口列表的一个数组(顺序是其创建时指定的),调用getMethods方法将返回包含所有这些接口中方法对象的数组

若是通过一个代理类(通过Proxy.getProxyClass返回一个类 or 通过Proxy.newProxyInstance返回对象的相关的类),则Proxy.isProxyClass返回true,否则返回false

代理类的保护域(java.security.ProtectionDomain)与由bootstrap类加载器加载系统类相同,因为代理类的代码是由可信任的系统代码生成,则保护域通常被授予 java.security.AllPermission

每个代理类有一个public构造器带一个参数,一个实现InvocationHandler接口的实现,为一个代理实例设置调用处理程序对象。而不是使用反射API去访问public constructor,一个代理实例也能够通过调用Proxy.newProxyInstance方法来创建,调用Proxy.getProxyClass方法与调用构造器和一个调用处理程序对象的组合

一个代理实例有下面属性:

给定一个代理实例proxy 并且 通过它的代理类Foo实现其中一个接口,则下面表达式返回true
proxy instanceof Foo
而且该类型转换(Foo)proxy也成功

每一个代理实例有与之关联的调用处理程序对象,通过它的构造函数设置

代理实例上一个接口方法调用将编码和转发到关联的调用处理程序对象的invoke方法上

hashCode、equals、toString方法声明在java.lang.Object中,在代理实例上调用时,将编码和转发到关联的调用处理程序对象invoke方法,以相同方式作为接口方法的调用被编码和转发
声明类的方法对象通过调用java.lang.Object。其他代理实例的public方法从java.lang.Object继承,并不通过代理类重写,因此,这些方法的调用就像java.lang.Object的实例

在多个代理接口中重复方法

当代理类的2个or多个接口包含相同的方法名和参数,那么代理类接口的顺序很重要。当一个重复的方法在代理实例上被调用,传递给调用处理程序对象的方法对象不一定是接口引用类型所指定的。这种限制存在,因为在生成的代理类中相应的实现方法不能确定是通过什么接口调用。因此,当一个代理实例上的重复方法被调用,重要的接口方法的方法对象(包含在代理类接口列表的方法传递到调用处理程序对象),不管引用类型通过哪个方法调用

如果一个代理接口包含一个与java.lang.Object的方法hashCode、equals、toString这些放相同方法名和参数签名,当该方法被调用时,方法对象传递到调用处理程序对象,该对象将有java.lang.Object当做它的声明类。换言之,java.lang.Object中public、non-final的方法通常在所有代理接口之前确定哪一个方法对象传递到调用处理程序对象上

注意,当一个重复的方法被转发到调用处理程序对象,invoke方法只能抛出受检查异常类型(在所有代理接口中的方法的throw从句可转换的一个异常类型),如果invoke抛出一个检查异常(一个不可转换成任意一个由代理接口的方法定义的异常类型),则抛出一个未检查异常。此限制意味着,并不是所有返回的异常类型由调用方法对象的getExceptionTypes的方法传递到invoke方法就一定可以通过invoke方法抛出

简单demo:

public interface Colorable {

public void value();

}

public class RedColor implements Colorable {

@Override
public void value() {
System.out.println("--------------red-------------");
}

}

public class ColorableProxy implements InvocationHandler {

private Colorable colorable;
private Colorable proxy;

public ColorableProxy(Colorable colorable) {
this.colorable = colorable;
this.proxy = (Colorable)Proxy.newProxyInstance(Colorable.class.getClassLoader(), new Class<?>[] { Colorable.class }, this);
}

public Colorable getProxy() {
return proxy;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
String methodName = method.getName();

System.out.println("===========starting invoke function:" + methodName + "==========");

Object result = method.invoke(colorable, args);

System.out.println("=========== invoke function:" + methodName + " success==========");
return result;
}

}

public class Main {

public static void main(String[] args) {

Colorable proxy = new ColorableProxy(new RedColor()).getProxy();
proxy.value();
}

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