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

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

1、什么是代理?

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

代理模式UML图:git

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

2、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为该方法的参数数组。这个抽象方法在代理类中动态实现。app

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

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.经过代理调用方法

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

一、须要动态代理的接口:

 

 

二、须要代理的实际对象

 

 

三、调用处理器实现类

 

 

四、测试

 

 

五、输出结果以下:

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

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

从使用代码中能够看出,关键点在:

经过跟踪提示代码能够看出:当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的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方法:

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

5、结论

到了这里,终于解答了:
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. 经过构造函数建立动态代理类实例,构造时调用处理器对象做为参数被传入。
相关文章
相关标签/搜索