JDK动态代理和CGLIB动态代理的异同

代理模式的概念和静态代理之前的文章已经说过了,没看过的可以点这里。

动态代理意义在于生成一个占位(又称为代理对象),用来代理真实的对象,来控制真实对象的访问。

举个例子,现在有一家软件公司,公司里面有软件工程师和商务,这个时候客户带着需求来到公司,会直接去找商务谈,客户认为商务就代表着公司,关系如下

JDK动态代理和CGLIB动态代理的异同_第1张图片

                                                                                   代理模式示意图

通过图可以看出来客户是通过商务去找软件工程师,商务的意义在哪里?商务可以进行谈判,根据客户的需求来谈判软件的价格,交付和时间点,如果谈判失败就直接结束了不会去找软件工程师。如果谈判成功再让软件工程师执行后续的操作。通过这个例子可以看出来,代理模式就是在访问真实的对象之前和之后做一些操作,比如在执行登录方法前后输出日志等等,还有可能是根据其它的规则来判断是否需要执行这个真实的对象去执行一些别的操作,比如mybatis的数据库操作(如果这篇文章有人看的话,后面会详细介绍)。

经过上面的例子,我们可以得出商务和软件工程师就是代理和被代理的关系。此时客户就是调用者,商务是代理对象而软件工程师就是真实对象。需要在调用者和真实对象中间加一个代理对象,代理对象需要和真实对象建立关系,所以建立代理对象需要几个步骤,

1、代理对象和真实对象建立代理关系

2、实现代理对象的代理逻辑

Java中有很多代理对象的技术,这里就讨论JDK和CGLIB的动态代理。

首先说一下JDK的动态代理,JDK的动态代理是java.lang.reflect.*包提供的方式,它必须要借助接口才可以实现(这里需要注意,如果只有实现类是无法完成代理的),首先我们先随便定义一个接口,如下图

JDK动态代理和CGLIB动态代理的异同_第2张图片

接着提供实现类

JDK动态代理和CGLIB动态代理的异同_第3张图片

按照上面的步骤来第一步建立代理对象和真实对象之间的关系,然后再实现代理逻辑。

在JDK动态代理中,要实现代理逻辑类就必须实现java.lang.reflect.InvocationHandler接口,实现里面的invoke方法。代码如下

JDK动态代理和CGLIB动态代理的异同_第4张图片

第一步,建立代理对象和真实对象之间的关系。这里使用的是bind的方法,首先用成员变量来保存存入的真实对象,接着通过如下代码建立并生成代理对象

JDK动态代理和CGLIB动态代理的异同_第5张图片

1、第一个参数是类加载器,我们使用的是真实对象的类加载器

2、第二个就是我们把生成的代理对象挂在那个接口之下,这样写就是放在真实对象的接口之下就是HelloWorld,如果真实对象没有实现接口这里会报错

3、第三个就是实现方法逻辑的代理类,就是是用哪一个类去代理的,this代表的是当前对象,它必须实现InvocationHandler接口的invoke方法,它是代理逻辑的实现方法。

第二步,实现代理逻辑方法,invoke方法可以实现代理逻辑,来解释下invoke方法的三个参数

JDK动态代理和CGLIB动态代理的异同_第6张图片

1、proxy就是代理对象,就是bind方法中返回的对象(这里可以调试看看,和bind方法返回的对象是hash值是一样的),这个方法基本很少用,想了解的话,可以看看这个大佬的文章

2、method是当前调度的方法也可以说是真实对象的方法

3、args就是调度方法的参数

当我们使用代理对象的调度方法的时候就会执行invoke方法

这行代码就是执行真实对象的方法,只不过是利用反射来实现的

和前面的例子进行对比,proxy就是商务对象,target是软件工程是,bind的方法就是建立这两者之间的关系,invoke就是商务逻辑,控制软件工程师的访问。

JDK动态代理和CGLIB动态代理的异同_第7张图片

 

打印结果如下

JDK动态代理和CGLIB动态代理的异同_第8张图片

在执行invoke方法的前后都可以去添加需要添加的方法,建议可以自己调试一下看看,看看执行步骤是怎么样的。

 

接下来说一下CGLIB动态代理

JDK动态代理必须提供接口才可以进行使用,有时候不能提供接口的时候,只能来使用第三方的技术,比如CGLIB动态代理。它的优势在于不需要提供接口,只要一个非抽象类就能实现动态代理。

首先看一下代码

JDK动态代理和CGLIB动态代理的异同_第9张图片

JDK动态代理和CGLIB动态代理的异同_第10张图片

这里使用的是CGLIB的加强者Enhancer,然后设置了超类的方法(setSuperclass),这里可以和JDK的获得真实对象的接口类比,其实就是设置将真实对象转换为什么类型的,之后和JDK代理一样设置代理类是什么(setCallback)。其中的this代表当前对象,要求这个对象实现了MethodInterceptor类的intercept方法,然后再生产代理对象返回。

在这个类里面的intercept就是代理逻辑的方法,参数说明注释中已经说明。和JDK实现的代理没有什么区别,需要注意的是intercept方法里面,和JDK代理相比多了一个methodProxy参数,这个参数是方法代理,通过代理对象来实现真实对象的方法和之前略有不同。那这里为什么会有method这个参数呢,我的理解是CGLIB也可以代理接口,这个时候就可以用到它了,和之前的JDK相同一致。

总结一下,JDK代理和CGLIB代理是很相似的,都是先生成代理对象,制定代理的逻辑类。而代理逻辑类要实现接口的一个方法,那么定义的方法就是代理对象的逻辑方法,可以控制真实对象的方法。区别是JDK代理只可以代理接口,而CGLIB既可以代理接口又可以代理非抽象类。

你可能感兴趣的:(设计模式)