Java 中的代理模式
代理模式
代理模式(Proxy Pattern)是一种结构型设计模式,它给某一个对象提供一个代理,并由代理对象控制原对象的引用。代理对象在客户端和目标对象之间起到中介作用。代理控制着对于原对象的访问,并允许在将请求提交给对象前后进行一些处理。
代理模式分类
在 Java 中,有两类代理模式:静态代理和动态代理。
静态代理
静态代理:代码编译时就已实现,编译完成后,代理类是一个实际的 class 文件。
静态代理实现较简单,只要代理对象对目标对象进行包装,即可实现增强功能,但静态代理只能为一个目标对象服务,如果目标对象过多,则会产生很多代理类。
实现方式
代理类与委托类实现同一接口,需要在代理类中硬编码
动态代理
动态代理:在运行时动态生成的,编译完成后没有实际的 class 文件,而是在运行时动态生成类字节码,并加载到 JVM 中。
其中,动态代理中又分为:JDK 动态代理和CGLIB 动态代理
JDK 动态代理
JDK 动态代理:JDK 动态代理利用了JDK API,动态地在内存中构建代理对象,从而实现对目标对象的代理功能。动态代理又被称为JDK代理或接口代理。
实现方式
代理类与委托类实现同一接口,代理类需要实现 InvocationHandler 接口,并重新 invoke 方法。
invoke 方法可以对委托方法进行增强
CGLIB 动态代理
CGLIB 代理:cglib(Code Generation Library)是一个第三方代码生成类库,运行时在内存中动态生成一个子类对象从而实现对目标对象功能的扩展。
cglib 是一个强大的高性能的代码生成包,它可以在运行期扩展 Java 类与实现 Java 接口。cglib 的底层是通过使用一个小而快的字节码处理框架 ASM,来转换字节码并生成新的类。
实现方式
代理类将委托类作为自己的父类并为其中的非 final 委托方法创建两个方法:
-
一个是与委托方法签名相同的方法,它在方法中会通过 super 调用委托方法;
-
另一个是代理类独有的方法。
在代理方法中,它会判断是否存在实现了 MethodInterceptor 接口的对象,若存在则将调用 intercept 方法对委托方法进行代理。
cglib 与 JDK 动态代理的区别
-
使用 JDK 动态代理的对象必须实现一个或多个接口;
-
使用 cglib 代理的对象,则无需实现接口,达到代理类无侵入。
注意,cglib 会继承目标对象,需要重写方法,所以目标对象不能为 final 类。
三种代理方式对比
代理方式 | JDK 静态代理 | JDK 动态代理 | CGLIB 动态代理 |
---|---|---|---|
优点 | 实现简单,容易理解 | 不需要硬编码接口,代码复用率高 | 可以在运行时对类或者是接口进行增强操作,且委托类无需实现接口 |
缺点 | 代理类需要硬编码接口,在实际应用中可能会导致重复编码,浪费存储空间并且效率较低 | 只能够代理实现了接口的委托类 | 不能对 final 类以及 final 方法进行代理 |
特点 | 底层使用反射机制进行方法的调用 | 底层将方法全部存入一个数组中,通过数组索引直接进行方法调用 |
参考: