Java JDK 动态代理使用及实现原理分析

http://blog.jobbole.com/104433/

一、什么是代理?

代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。

代理模式UML图:

为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。Java 动态代理机制以巧妙的方式近乎完美地实践了代理模式的设计理念。

二、Java 动态代理类

Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:

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

[java] view plain copy

  1. publicobject invoke(Object obj,Method method, Object[] args)

在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。这个抽象方法在代理类中动态实现。

(2)Proxy:该类即为动态代理类,其中主要包含以下内容:

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

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

static Object newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)

所谓DynamicProxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然,这个DynamicProxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。

在使用动态代理类时,我们必须实现InvocationHandler接口

通过这种方式,被代理的对象(RealSubject)可以在运行时动态改变,需要控制的接口(Subject接口)可以在运行时改变,控制的方式(DynamicSubject类)也可以动态改变,从而实现了非常灵活的动态代理关系。

动态代理步骤
1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法
2.创建被代理的类以及接口
3.通过Proxy的静态方法
newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理
4.通过代理调用方法

三、JDK的动态代理怎么使用?

1、需要动态代理的接口:

 

 

2、需要代理的实际对象

 

 

3、调用处理器实现类

 

 

4、测试

 

 

5、输出结果如下:

演示demo下载地址:http://download.csdn.net/detail/xunzaosiyecao/9597388

四、动态代理怎么实现的?

从使用代码中可以看出,关键点在:

通过跟踪提示代码可以看出:当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用。

 

也就是说,当代码执行到:
subject.SayHello(“jiankunking”)这句话时,会自动调用InvocationHandlerImpl的invoke方法。这是为啥呢?
 
======横线之间的是代码跟分析的过程,不想看的朋友可以直接看结论======
以下代码来自:JDK1.8.0_92
既然生成代理对象是用的Proxy类的静态方newProxyInstance,那么我们就去它的源码里看一下它到底都做了些什么?
我们再进去getProxyClass0方法看一下:

真相还是没有来到,继续,看一下proxyClassCache

 

 

奥,原来用了一下缓存啊

那么它对应的get方法啥样呢?


我们可以看到它调用了 supplier.get(); 获取动态代理类,其中supplier是Factory,这个类定义在WeakCach的内部。

 

来瞅瞅,get里面又做了什么?

发现重点还是木有出现,但我们可以看到它调用了valueFactory.apply(key, parameter)方法:

 


通过看代码终于找到了重点:

 


那么接下来我们也使用测试一下,使用这个方法生成的字节码是个什么样子:

我们用jd-jui 工具将生成的字节码反编译:

 


这就是最终真正的代理类,它继承自Proxy并实现了我们定义的Subject接口
也就是说:

 

这里的subject实际是这个类的一个实例,那么我们调用它的:
就是调用我们定义的InvocationHandlerImpl的 invoke方法:

======横线之间的是代码跟分析的过程,不想看的朋友可以直接看结论=======

五、结论

到了这里,终于解答了:
subject.SayHello(“jiankunking”)这句话时,为什么会自动调用InvocationHandlerImpl的invoke方法?

因为JDK生成的最终真正的代理类,它继承自Proxy并实现了我们定义的Subject接口,在实现Subject接口方法的内部,通过反射调用了InvocationHandlerImpl的invoke方法。

包含生成本地class文件的demo:http://download.csdn.net/detail/xunzaosiyecao/9597474

通过分析代码可以看出Java 动态代理,具体有如下四步骤:

    1. 通过实现 InvocationHandler 接口创建自己的调用处理器;
    2. 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
    3. 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
    4. 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
posted @ 2017-08-17 23:36  YDDMAX  阅读(331)  评论(0编辑  收藏  举报