本文转载自微信公众号「程序新视界」,作者丑胖侠二师兄 。转载本文请联系程序新视界公众号。
创新互联公司是一家专注于网站设计制作、成都网站建设与策划设计,南木林网站建设哪家好?创新互联公司做网站,专注于网站建设10余年,网设计领域的专业建站公司;建站业务涵盖:南木林等地区。南木林做网站价格咨询:18982081108
学习不用那么功利,二师兄带你从更高维度轻松阅读源码~
随着对Nacos源码的深入阅读,感觉越来越有意思了,大量的设计模式和基础知识点都在其中被运用。不论你是否阅读源码,都值得借鉴一下Nacos的运用案例。
今天这篇文章,给大家介绍一下Nacos Client中对代理模式的运用。阅读这篇文章,你可以不懂Nacos源码,但能够学到代理模式的运用;如果你准备阅读Nacos源码,不仅可以学到代理模式的案例,还可以更加深刻的感知到Nacos中的设计思想。
通俗的来讲,代理模式就是让别人(代理)帮忙做你并不关心的事,作用就相当于日常生活中的中介。
比如,日常生活中,你想买辆车,你可以直接去自己挑选、质检等,但这个过程会耗费你大量的时间和精力。那么,此时你就可以找一个代理,来帮忙实现挑选、质检的事情。
对于软件设计来说,代理模式的定义为:代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。
在不使用代理模式时,我们大概是这样使用一个接口:图片
客户端在使用CarService接口时需要创建CarServiceImpl类的实例,然后进行业务逻辑处理。
但在某些场景下,一个客户类不想或者不能直接引用一个委托对象(CarServiceImpl),此时代理类对象可以在客户类和委托对象之间起到中介的作用,并提供相同的功能。
如果提供相同的功能,那么代理类和委托类就需要实现相同的接口。此时,上图就演变成了代理模式:
代理模式
在代理模式的图中,对比普通的直接使用,新增了代理类,并且代理类持有了委托类(真实对象)的引用。代理类本身并不真正实现服务,而是通过调用委托类的相关方法,来提供特定的服务,所以要持有真实类的引用。
代理类可以在业务功能执行的前后加入一些公共的服务,比如负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。
代理模式中的角色:
以上面的结构图为例,来看看代理模式的代码实现。
定义抽象主题类(CarService)、具体主题类(CarServiceImpl)、代理类(CarServiceProxy):
- // 抽象主题类
- public interface CarService {
- // 选车
- Car chooseCar();
- // 质量检查
- boolean qualityCheck();
- }
- // 具体主题类
- public class CarServiceImpl implements CarService {
- @Override
- public Car chooseCar() {
- System.out.println("真实操作:选车");
- return new Car();
- }
- @Override
- public boolean qualityCheck() {
- System.out.println("真实操作:质量检测");
- return true;
- }
- }
- // 代理类
- public class CarServiceProxy implements CarService {
- private CarServiceImpl real;
- public CarServiceProxy() {
- real = new CarServiceImpl();
- }
- @Override
- public Car chooseCar() {
- System.out.println("代理类CarServiceProxy选车:先添加一些日志");
- return real.chooseCar();
- }
- @Override
- public boolean qualityCheck() {
- System.out.println("代理类CarServiceProxy质量检测:先添加一些日志");
- return real.qualityCheck();
- }
- }
对应的客户端测试类:
- public class Client {
- public static void main(String[] args) {
- CarService carService = new CarServiceProxy();
- carService.chooseCar();
- carService.qualityCheck();
- }
- }
直接使用代理类,就可以完成预期的工作。
执行程序,打印日志如下:
可以看出,在真实的操作之前,可以通过代理类添加一些其他的操作。
上面了解了代理模式的基本知识以及实例,下面就来看看Nacos中是如何实现代理模式的。
Nacos Client与注册中心进行通信采用了两种通信协议:HTTP协议和gRPC协议。这两个协议实现了共同的抽象主题类NamingClientProxy,具体主题类有NamingHttpClientProxy和NamingGrpcClientProxy,分别对应Http协议和gRPC协议实现。
此时,Nacos考虑到要支持通过配置来灵活选择具体的通信协议,而这个功能呢又没办法让这两个具体的主题类来实现,因此就产生了一个代理类NamingClientProxyDelegate来完成一些预先的处理和判断。
整个代理模式的使用类图如下:
代理模式
通过上图可以发现,Nacos的代理模式使用与标准的代理模式还有一些区别。
首先,NamingClientProxyDelegate同时代理了具体主题类,这可能考虑的是方便通信协议的配置切换。同时,在代理类中还处理了一些事件监听等额外功能。
其次,说话Nacos这块的命名并不友好,比如抽象主题直接以Proxy为后缀,容易让人混淆。这就导致与代理模式中的代理类命名冲突,于是将代理类的后缀替换为了Delegate。
上图中的客户类便是NacosNamingService,在其中实现了代理类的初始化操作,具体代码实现如下:
- public class NacosNamingService implements NamingService {
- // ...
- private NamingClientProxy clientProxy;
- private void init(Properties properties) throws NacosException {
- // ...
- this.clientProxy = new NamingClientProxyDelegate(this.namespace, serviceInfoHolder, properties, changeNotifier);
- }
- @Override
- public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
- NamingUtils.checkInstanceIsLegal(instance);
- clientProxy.registerService(serviceName, groupName, instance);
- }
- // ...
- }
抽象主题类NamingClientProxy为接口,部分代码如下:
- public interface NamingClientProxy extends Closeable {
- void registerService(String serviceName, String groupName, Instance instance) throws NacosException;
- void deregisterService(String serviceName, String groupName, Instance instance) throws NacosException;
- // ...
- }
代理类NamingClientProxyDelegate部分实现如下:
- public class NamingClientProxyDelegate implements NamingClientProxy {
- // ...
- private final NamingHttpClientProxy httpClientProxy;
- private final NamingGrpcClientProxy grpcClientProxy;
- public NamingClientProxyDelegate(String namespace, ServiceInfoHolder serviceInfoHolder, Properties properties,
- InstancesChangeNotifier changeNotifier) throws NacosException {
- // ...
- this.httpClientProxy = new NamingHttpClientProxy(namespace, securityProxy, serverListManager, properties,
- serviceInfoHolder);
- this.grpcClientProxy = new NamingGrpcClientProxy(namespace, securityProxy, serverListManager, properties,
- serviceInfoHolder);
- }
- // ...
- }
可以看出,代理类实现了NamingClientProxy接口,同时持有了NamingHttpClientProxy和NamingGrpcClientProxy的对象引用,并且对它们进行了初始化操作。
关于NamingHttpClientProxy和NamingGrpcClientProxy的代码我们就不再展示,它们首先继承了AbstractNamingClientProxy抽象类,该抽象类实现NamingClientProxy接口。
从整体上来说,Nacos中对代理模式的运用还是比较灵的,结合场景一个代理类代理了两个具体实现类,但同时在命名方面的问题,还有待商榷。
在学习使用代理模式时,经常会有朋友与装饰器模式相混淆。这里就简单聊一下它们直接的区别。
装饰器模式中,装饰者(decorator)和被装饰者(decoratee)都实现同一个接口。代理模式中,代理类(proxy class)和真实处理的类(real class)都实现同一个接口。而且两者都对类的方法进行扩展,看起来边界的确比较模糊。
但还是有一些区别点的:
代理模式在日常业务代码中还是比较少见的,本文我们重点介绍了静态代理模式及在Nacos中的运用。关于动态代理,在Spring的框架中可以看到很多实例,有机会我们再进行讲解。而Nacos中对代理模式的运用算是比较灵活,同时也并不是那么完美。这或许也提供了我们对代理模式认知的另外一个视角。
网页名称:Nacos竟然是这样使用代理模式的?
网站链接:http://www.shufengxianlan.com/qtweb/news5/290305.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联