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

jdk 动态代理源码分析

2016-11-10 16:35 459 查看
1、jdk 的动态代理调用类在



该代理类提供了用于创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。

动态代理类(下面简称为代理类)是一个类,它实现了在创建类时在运行时指定的接口列表,其行为如下所述。 代理接口是由代理类实现的接口。 代理实例是代理类的实例。 每个代理实例都有一个关联的调用处理程序对象,它实现了InvocationHandler接口。 通过其代理接口之一在代理实例上的方法调用将被分派到实例的调用处理程序的invoke方法,传递代理实例,标识被调用的方法的java.lang.reflect.Method对象,以及数组 包含参数的Object类型。 调用处理程序适当地处理编码的方法调用,并且返回的结果将作为对代理实例的方法调用的结果而返回。

代理类的特性:

1、代理类的接口是public 的话,代理类实例就是public,final和抽象的

2、代理类的接口不是public 的话,代理类实例就不是public,final和非抽象的

3、未指定了代理类的非限定名称。 但是,以字符串“$ Proxy”开头的类名的空间应该保留给代理类。

4、代理类继承了java.lang.reflect.Proxy

5、代理类以相同的顺序完全实现在其创建时指定的接口。

6、如果代理类实现了非公共接口,那么它将在与该接口相同的包中定义。否则,代理类的包也是未指定的。请注意,包密封不会阻止代理类在运行时在特定包中成功定义,也不会阻止由同一类装入器定义的类和具有特定签名者的相同包。
7、由于代理类实现了在其创建时指定的所有接口,在其Class对象上调用getInterfaces将返回一个包含相同的接口列表的数组(按其创建时指定的顺序),在其Class对象上调用getMethods将返回一个数组的Method对象,包括这些接口中的所有方法,并且调用getMethod将在代理接口中找到预期的方法。
8、Proxy.isProxyClass方法将返回true,如果它传递一个代理类 - 一个由Proxy.getProxyClass返回的类或由Proxy.newProxyInstance返回的对象的类 - 否则返回false。
9、代理类的java.security.ProtectionDomain与引导类加载器加载的系统类(如java.lang.Object)的java.security.ProtectionDomain相同,因为代理类的代码是由受信任的系统代码生成的。此保护域通常会被授予java.security.AllPermission。
10、每个代理类都有一个公共构造函数,它接受一个参数,即接口InvocationHandler的实现,以设置代理实例的调用处理程序。而不是必须使用反射API访问公共构造函数,还可以通过调用Proxy.newProxyInstance方法创建代理实例,该方法将调用Proxy.getProxyClass的操作与调用处理程序的构造函数相结合。

代理实例的特性:

1、给定代理实例代理和其代理类Foo实现的接口之一,以下表达式将返回true:

proxy instanceof Foo

2、和下面的cast操作将成功(而不是抛出一个ClassCastException):
(Foo) proxy


3、每个代理实例都有一个关联的调用处理程序,传递给它的构造函数。 静态Proxy.getInvocationHandler方法将返回与作为其参数传递的代理实例相关联的调用处理程序。
4、代理实例上的接口方法调用将被编码并调度到调用处理程序的invoke方法,如该方法的文档中所述。
5、调用在代理实例上的java.lang.Object中声明的hashCode,equals或toString方法将被编码并以与接口方法调用被编码和分派相同的方式被分派到调用处理程序的invoke方法,如上所述。 传递给invoke的Method对象的声明类将是java.lang.Object。 从java.lang.Object继承的代理实例的其他公共方法不会被代理类覆盖,因此这些方法的调用与对java.lang.Object的实例的调用类似。

多代理接口中重复的方法
1、当代理类的两个或多个接口包含具有相同名称和参数签名的方法时,代理类接口的顺序变得重要。当在代理实例上调用这样的重复方法时,传递给调用处理程序的方法对象不一定是其声明类可从通过调用代理的方法的接口的引用类型分配的那个。存在此限制,因为在生成的代理类中的相应方法实现无法确定它通过哪个接口被调用。因此,当在代理实例上调用重复方法时,在代理类的接口列表中包含方法(直接或通过超级接口继承)的最前面接口中的方法的方法对象被传递到调用处理程序的调用方法,而不管方法调用发生的引用类型。

2、如果代理接口包含与java.lang.Object的hashCode,equals或toString方法具有相同名称和参数签名的方法,当在代理实例上调用此类方法时,传递给调用处理程序的Method对象将有java.lang.Object作为它的声明类。换句话说,java.lang.Object的公共非最终方法在所有代理接口之前逻辑地先于确定哪个Method对象传递给调用处理程序。

3、还要注意,当重复方法被分派到调用处理程序时,invoke方法只能抛出可被分配给方法的throws子句中的其中一个异常类型的所有可调用的异常类型通过。如果invoke方法抛出一个无法分配给该方法在其中一个代理接口中声明的任何可以被调用的异常类型的检查异常,则在代理实例上的调用将抛出未检查的UndeclaredThrowableException。这种限制意味着,并非所有通过对传递给invoke方法的Method对象调用getExceptionTypes返回的异常类型都可以被invoke方法成功抛出。

列子:

1 package com.test;
2
3 /**
4  * Created by Administrator on 2016/11/10.
5  */
6 public interface CountService {
7     int count();
8 }


1 package com.test;
2
3 /**
4  * Created by Administrator on 2016/11/10.
5  */
6 public class CountServiceImpl implements CountService {
7     private int count =0;
8     public int count() {
9         return count++;
10     }
11 }


public class DynamicProxyPerformanceTest {

public static void main(String[] args) throws Exception {
//要代理的类:
CountService delegate = new CountServiceImpl();
//jdk 代理
CountService jdkProxy = createJdkDynamicProxy(delegate);
test(jdkProxy, "Run JDK Proxy: ");
}
private static void test(CountService service, String label)
throws Exception {
service.count(); // warm up
}
private static CountService createJdkDynamicProxy(final CountService delegate) {
CountService jdkProxy = (CountService) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
new Class[] { CountService.class }, new JdkHandler(delegate));
return jdkProxy;
}

private static class JdkHandler implements InvocationHandler {

final Object delegate;

JdkHandler(Object delegate) {
this.delegate = delegate;
}

public Object invoke(Object object, Method method, Object[] objects)
throws Throwable {
return method.invoke(delegate, objects);
}
}

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