【设计模式】代理模式
理解设计模式,提升代码复用性 #生活技巧# #学习技巧# #编程学习技巧#
文章目录 代理模式原理静态代理优缺点 动态代理实现方式JDK动态代理生成对象步骤CGLib采用了FastClass机制JDK和CGLib对比实现方式生成字节码调用代理方法 静态代理与动态代理区别代理模式的优缺点代理模式的应用场景1. 业务系统的非功能性需求开发2. 代理模式在RPC、缓存中的应用代理模式原理
代理模式(Proxyy)就是在不改变原始类(或叫做被代理类)代码的情况下,通过引入代理类来给原始类附加功能。
静态代理
静态代理在使用时,需要定义接口或者父类,被代理对象(即目标对象)一起实现相同的接口或者是继承相同父类应用实例。
优缺点
优点:
1. 在不修改目标对象的功能前提下,能通过代理对象对目标进行拓展
缺点:
1. 因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,增加了不必要的开发成本。
2. 一旦接口增加方法,目标对象与代理对象都要维护。
动态代理
动态代理可以解决上述静态代理的缺点问题。
所谓动态代理,就是我们不事先为每个原始类编写代理类,而是在运行的时候,动态地创建原始类对应的代理类,然后在系统中用代理类替换掉原始类。
实现方式
JDK实现:InvocationHandler接口CGLib实现:MethodInterceptor接口CGLIb要求目标代理类中不能有final关键字修饰的方法
JDK动态代理生成对象步骤
获取被代理对象的引用,并获取它的所有接口,通过反射获取。JDK动态代理类重新生成一个新类,同时新类实现被代理类实现的所有接口。动态生成java代码,新加的业务逻辑方法由一定的代码逻辑调用,$Proxy0。编译新生成的java代码.class文件。重新加载到JVM中。CGLib采用了FastClass机制
为代理类和被代理类各生成一个class。class会为代理类和被代理类方法分配一个index。idnex当做入参,FastClass就可以直接定位要调用的方法。JDK和CGLib对比
实现方式 JDK实现了被代理的接口CGLib继承了被代理的接口 生成字节码 JDK直接生成字节码CGLib通过asm框架生成class字节码CGlib生成代理类比JDK动态代理效率低 调用代理方法 JDK通过反射机制调用CGLib通过FastClass机制直接调用CGLib执行效率比JDK高静态代理与动态代理区别
静态代理
只能通过手动完成代理操作,硬编码被代理类新增了方法,代理类也要同步增加,违背了开闭原则动态代理
采用运行时动态生成代码的方式,反射实现对目标类的增加逻辑拓展,只需要新增策略类即可完成,无需修改代理类的代码代理模式的优缺点
优点
能将代理对象与真实被调用目标对象分离在一定程度上降低了系统的耦合度,拓展性好起到保护目标对象的作用增强目标对象的功能缺点
造成了系统中类的数量增加增加了代理对象,会导致请求处理速度变慢增加了系统的复杂度代理模式的应用场景
1. 业务系统的非功能性需求开发
代理模式最常用的一个应用场景就是,在业务系统中开发一些非功能性需求,比如:监控、统计、鉴权、限流、事务、幂等、日志。我们将这些附加功能与业务功能解耦,放到代理类中统一处理,让程序员只需要关注业务方面的开发。实际上,前面举的搜集接口请求信息的例子,就是这个应用场景的一个典型例子。
如果你熟悉 Java 语言和 Spring 开发框架,这部分工作都是可以在 Spring AOP 切面中完成的。前面我们也提到,Spring AOP 底层的实现原理就是基于动态代理。
2. 代理模式在RPC、缓存中的应用
实际上,RPC框架也可以看做是一种代理模式,GoF的《设计模式》一书中把它称作远程代理。通过远程代理,将网络通信,数据编码等细节隐藏起来。客户端在使用RPC服务的时候,就像在使用本地函数一样,无需了解跟服务器交互的细节。除此之外,RPC服务的开发者也只需要开发业务逻辑,就像开发本地使用的函数一样,不需要关注客户端的交互细节。
我们再来看代理模式在缓存中的应用。假设我们要开发一个接口请求的缓存功能,对于某些接口请求,如果入参相同,在设定的过期时间内,直接返回缓存结果,而不用重新进行逻辑处理。比如,针对获取用户个人信息的需求,我们可以开发两个接口,一个支持缓存,一个支持实时查询。对于需要实时数据的需求,我们让其调用实时查询接口,对于不需要实时数据的需求,我们让其调用支持缓存的接口。那如何来实现接口请求的缓存功能呢?最简单的实现方法就是刚刚我们讲到的,给每个需要支持缓存的查询需求都开发两个不同的接口,一个支持缓存,一个支持实时查询。但是,这样做显然增加了开发成本,而且会让代码看起来非常臃肿(接口个数成倍增加),也不方便缓存接口的集中管理(增加、删除缓存接口)、集中配置(比如配置每个接口缓存过期时间)。
针对这些问题,代理模式就能派上用场了,确切地说,应该是动态代理。如果是基于 Spring 框架来开发的话,那就可以在 AOP 切面中完成接口缓存的功能。在应用启动的时候,我们从配置文件中加载需要支持缓存的接口,以及相应的缓存策略(比如过期时间)等。当请求到来的时候,我们在 AOP 切面中拦截请求,如果请求中带有支持缓存的字段(比如 http://…?..&cached=true),我们便从缓存(内存缓存或者 Redis 缓存等)中获取数据直接返回。
网址:【设计模式】代理模式 https://www.yuejiaxmz.com/news/view/122868
相关内容
【设计模式】策略模式 ( 简介【设计模式】状态模式 ( 简介
【设计模式】解释器模式 ( 简介
设计模式第11讲——外观模式(Facade)
设计模式第14讲——享元模式(Flyweight)
设计模式
【设计模式】观察者模式 ( 简介
设计模式生活实例
图解设计模式之发布
从生活中领悟设计模式