代理模式
介绍
代理模式(Proxy Pattern)又叫委托模式,是为某个对象提供一个代理对象,并且由代理对象控制对原对象的访问。代理对象在客户端和目标对象之间起到中介作用,代理模式属于结构性设计模式。使用代理模式主要有两个目的:一是保护目标对象,二是增强目标对象(执行目标方法前后都可以做额外的处理)。
分类
- 静态代理:由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
- 动态代理:动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件(字节码在内存中动态生成的),代理类和委托类的关系是在程序运行时确定。
静态代理
类图
类图说明
Subject
:抽象主题角色:可以是抽象类,也可以是接口。抽象主题是一个普通的业务类型,无特殊要求。
RealSubject
: 具体主题角色:也叫做被委托角色或被代理角色,是业务逻辑的具体执行者。
Proxy
:代理主题角色:也叫做委托类或代理类。它负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在具体主题角色处理完毕。
示例代码
抽象主题Subject
类
1 | public interface Subject { |
具体主题角色RealSubject
类
1 | public class RealSubject implements Subject{ |
代理主题角色Proxy
类
1 | public class Proxy implements Subject{ |
测试代码结果
从示例代码可以看出:
- 如果我们的接口新增一个方法,那么所有的实现类都需要实现这个方法,所有的代理类也需要实现这个方法。
- 代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。
- 代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。
因为以上的一些瑕疵,所以才出现了动态代理。
JDK动态代理
类图
代码
抽象主题Subject
类
1 | public interface Subject { |
具体主题角色RealSubject
类
1 | public class RealSubject implements Subject { |
JDK动态代理类
1 | public class JdkProxy implements InvocationHandler { |
测试截图
由此我们可以看出:
- 动态代理类和被代理类必须继承同一个接口。
- 动态代理只能对接口中声明的方法进行代理。
- 每一个动态代理实例都有一个关联的
InvocationHandler
。 - 通过代理实例调用方法,方法调用请求会被转发给
InvocationHandler
的invoke
方法。 - 只能代理声明在接口中的方法。
CGLIB动态代理
类图
代码
具体主题角色RealSubject
类
1 | public class RealSubject{ |
CGLIB动态代理类
1 | public class CglibProxy implements MethodInterceptor { |
测试截图
我们发现cglib动态代理不需要代理对象实现任何接口就能实现对对象的代理,这是和cglib的不同之一。
静态代理和动态代理的区别
- 静态代理只能通过手动完成代理操作,如果被代理类增加新的方法,代理类需要同步新增,违背开闭原则。
- 动态代理采用在运行时动态生成代码的方式,取消了对被代理类的扩展限制,遵循开闭原则。
- 若动态代理要对目标类的增强逻辑扩展,结合策略模式,只需要新增策略类便可完成,无需修改代理类的代码。
代理模式和装饰器模式的区别
- 代理模式通常在一个代理类中创建一个被代理类的对象,而装饰器模式通常的做法是将原始对象作为一个参数传给装饰者的构造器。
- 代理模式关注于控制对对象的访问,然而饰器器模式关注于在一个对象上动态的添加方法。
- 代理模式注重的是对对象的某一功能的流程把控和辅助,它可以控制对象做某些事,重心是为了借用对象的功能完成某一流程,而非对象功能如何;装饰器模式注重的是对对象功能的扩展,不关心外界如何调用,只注重对对象功能加强,装饰后还是对象本身。
本章节主要讲解代理模式,至于jdk
动态代理和cglib
动态代理的原理本章无需深入过多,以后会专门讲解jdk
动态代理和cglib
动态代理的原理。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 故友的学习录!
评论