做开发的都知道,编程语言可以从运行时还是编译时检查分为动态类型和静态类型。对于Java来说,通常认为它是静态的强类型语言,但是因为Java提供反射的机制,也具备了部分动态类型语言的能力。这一节,我们就讲一讲Java的动态代理。

      动态代理是一种用于运行时动态构建代理,动态处理代理方法调用的机制。它首先是一种机制。在设计模式中有一种模式叫做代理模式(Proxy Pattern),和动态代理类似,其中代理可以看作是对调用目标的一个包装,通过代理完成对目标对象的调用。这其实也是一种解耦。

      实现动态代理的机制有很多,比如JDK自身提供的动态代理JDK Proxy(利用Java语言的反射机制),其他方式有ASM,CGLIB<基于ASM>,Javassit等。动态代理机制主要应用有面向切面AOP、拦截器、RPC调用、日志、事务等等。

        我们先来探究JDK Proxy机制<基于反射>----通过接口。新版本也开始结合ASM机制。它涉及到最重要的类和接口就是Proxy和InvocationHandler。先熟悉他们一下。

        Proxy这个类的作用就是用来动态创建一个代理对象的类,它最常用到的方法是newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)

 

SuppressWarnings原理 java java proxy原理_动态代理

 InvocationHandler接口只有一个方法,每个动态代理类都必须实现这个接口。

SuppressWarnings原理 java java proxy原理_字节码_02

有了初印象之后,我们再来看看一个简单的JDK Proxy例子。

SuppressWarnings原理 java java proxy原理_动态代理_03

CGLIB生成动态代理的机制<基于ASM>---通过类继承:

    通过生成类的子类作为代理对象,它可以在运行期扩展Java类与实现Java接口。

    CGLIB创建某个类A的动态代理类模式是:

          1.   查找A上的所有非final 的public类型的方法定义;

          2.   将这些方法的定义转换成字节码;

          3.   将组成的字节码转换成相应的代理的class对象;

          4.   实现 MethodInterceptor接口,用来处理 对代理类上所有方法的请求(这个接口和JDK动态代理InvocationHandler的功能和角色是一样的)


顺便说一下Spring AOP使用不同的技术在运行时创建代理:JDK Proxy和CGLIB。

       它的机制是,如果目标类实现了一个或多个接口,那么spring将创建一个实现了每个接口的JDK动态代理。如果目标类没有实现接口,Spring将使用CGLIB动态创建一个新类,它是目标的子类("extends")。这导致一个重要的区别:JDK Proxy无法转为原始的目标类,因为它只是一个动态代理,恰好实现了与目标相同的接口。而CGLIB可以像目标类本身一样。

JDK Proxy的优势:

      最小化依赖关系;

      平滑进行JDK版本升级,而字节码类库通常需要更新以保证新版本的java使用;

      代码实现简单。

基于CGLIB框架的优势:

     有的时候调用目标可能不便实现额外接口,从而在运行期扩展Java类与实现Java接口;从某种角度看,限定调用者实现接口是有些侵入性的实践,类似 cglib 动态代理就没有这种限制;

      只操作我们关心的类,而不必管其他相关类;

      高性能。