一、什么是代理模式
代理模式(Proxy Design Pattern):代理模式是结构型模式,代理模式通过非侵入式的方式给原始类附加功能。
二、代理模式的作用
假设有如下代码:
系统需要针对操作处理记录日志,上述代码通过侵入式的方式来实现了日志的记录功能,每一个需要记录日志的方法都需要增加相关代码。
不过也如代码所示,代码侵入性强,且功能性代码和业务代码高度耦合,后期如果日志操作变更,或者记录参数改动,或者需要进行更换日志框架,耦合性的代码会带来很大的问题。
这时候就可以使用代理模式来避免这些问题,通过代理模式可实现代码的无侵入日志功能。
三、静态代理
静态代理分为两种
1、被代理类实现了接口,代理类可以通过实现相同的接口,进行功能附加
2、被代理类没有实现接口,代理类可以通过继承被代理类,进行功能附加
3.1、和被代理类实现同一个接口实现代理
当被代理类实现了接口,代理类实现相同的接口进行功能增强,代码如下:
上述代码主要三个类:**IOrderController**
:API 统一接口定义**OrderController**
:实现了 IOrderController
并提供具体 API 实现**ProxyOrderController**
:实现了 IOrderController
同时持有 OrderController
实例对象,可以在 OrderController
无感知的情况下,增加相关功能
3.2、通过继承的方式实现代理
代码如下
上述代码主要二个类:**OrderController**
:提供具体 API 实现**ProxyOrderController**
:继承了 OrderController
,重写相关 API 实现,可以再调用父类方法前后进行功能增强。
静态代理的局限性
静态代理虽然能在无修改原有代码的基础上进行功能附加,但是需要实现重写或者继承被代理类,且实现的代理类只能对某个被代理类进行功能附加,如果有其他被代理类,需要在重新写一个新的代理类。
四、动态代理
动态代理同样存在两种方式:
1、接口方式的动态代理
2、继承方式的动态代理
4.1、接口方式的动态代理
接口方式的动态代理使用 JDK 自带的来实现
jdk 实现动态代理要点
1、代理对象需要实现 InvocationHandler
重写 invoke
2、被代理对象需要实现有接口
直接来看上述日志功能优化后,日志代理类 OperationLogProxy 代码,代码如下:
该代理类能够代理任何符合标准(被代理类只要有实现接口)的被代理类,包括代理类中的所有方法。突破静态代理只能针对单一对象进行代理的局限性。
简单案例:通过上述日志代理类 **OperationLogProxy **
进行代码增强
jdk 动态代理的原理
在代码运行中,Jdk 会生成一个 **$Proxy**
开头的代理对象,例如下面
下面通过反编译的方式来查看 JVM 生成的代理对象 **$Proxy0**
相关生成反编译代码的代码如下:
生成后的 $Proxy 文件部分代码如下
通过图片能够得出 jdk 动态代理的原理
JVM 通过字节码生成了一个新的类,该类继承了被代理对象的接口(如:IOrderController
),同时持有了我们写的代理类(如:OperationLogProxy
)
字节码生成的类持有了代理类(如:OperationLogProxy
)同时持有了 被代理类 (如:IOrderController
) 的实例对象。
字节码生成的类重写了被代理类接口的所有方法,这些方法的调用都需要使用反射来调用,而调用的顺序在代理类(如:OperationLogProxy
) 中的 invoke
方法。
再来回顾下 **OperationLogProxy#invoke**
在反射执行调用前,我们可以在他的前后插入我们需要执行的逻辑,
4.2、继承的方式实现动态代理
JDK 本身只提供了接口方式动态代理,继承方式的动态代理可以使用 cglib 来实现。
相关实现代码如下:
单纯从类的数量来说,比较于 JDK 动态代理, cglib 动态代理 减少了接口类的定义。
cglib 动态代理原理
通过 Cglib 提供的测试工具,将cglib 字节码操作后的类存入到本地磁盘
部分代码如下:
cglib 的原理
通过字节码生成一个新的类OrderControllerEnhancerByCGLIBfe4a213继承被代理类OrderController,同时持有代理类CglibOperationLogProxy (也就是 MethodInterceptor
) 的实例对象。
方法调用的子类OrderControllerEnhancerByCGLIBfe4a213,然后调用的CglibOperationLogProxy (也就是 MethodInterceptor
) , 最后调用的代理类OrderController。
在调用链路中,优先调用的 CglibOperationLogProxy (也就是 MethodInterceptor
) 中的 interceptor 方法,最后调用的 OrderController,
而代码的增强在 interceptor 方法中完成,从而实现代码无侵入性的增强。
【公众号】花好夜猿