关于spring-cloud:跟二师兄学Nacos吧EXT04篇-Nacos竟然是这样使用代理模式的

35次阅读

共计 5273 个字符,预计需要花费 14 分钟才能阅读完成。

学习不必那么功利,二师兄带你从更高维度轻松浏览源码~

随着对 Nacos 源码的深刻浏览,感觉越来越有意思了,大量的设计模式和根底知识点都在其中被使用。不管你是否浏览源码,都值得借鉴一下 Nacos 的使用案例。

明天这篇文章,给大家介绍一下 Nacos Client 中对代理模式的使用。浏览这篇文章,你能够不懂 Nacos 源码,但可能学到代理模式的使用;如果你筹备浏览 Nacos 源码,不仅能够学到代理模式的案例,还能够更加粗浅的感知到 Nacos 中的设计思维。

代理模式简介

艰深的来讲,代理模式就是让他人(代理)帮忙做你并不关怀的事,作用就相当于日常生活中的中介。

比方,日常生活中,你想买辆车,你能够间接去本人筛选、质检等,但这个过程会消耗你大量的工夫和精力。那么,此时你就能够找一个代理,来帮忙实现筛选、质检的事件。

对于软件设计来说,代理模式的定义为:代理模式给某一个对象提供一个代理对象,并由代理对象管制对原对象的援用。艰深的来讲代理模式就是咱们生存中常见的中介。

代理模式的构造

在不应用代理模式时,咱们大略是这样应用一个接口:

客户端在应用 CarService 接口时须要创立 CarServiceImpl 类的实例,而后进行业务逻辑解决。

但在某些场景下,一个客户类不想或者不能间接援用一个委托对象(CarServiceImpl),此时代理类对象能够在客户类和委托对象之间起到中介的作用,并提供雷同的性能。

如果提供雷同的性能,那么代理类和委托类就须要实现雷同的接口。此时,上图就演变成了代理模式:

在代理模式的图中,比照一般的间接应用,新增了代理类,并且代理类持有了委托类(实在对象)的援用。代理类自身并不真正实现服务,而是通过调用委托类的相干办法,来提供特定的服务,所以要持有实在类的援用。

代理类能够在业务性能执行的前后退出一些公共的服务,比方负责为委托类预处理音讯、过滤音讯、把音讯转发给委托类,以及预先对返回后果的解决等。

代理模式中的角色:

  • 形象主题类(Subject):申明了指标对象和代理对象的独特接口,在任何能够应用指标对象的中央都能够应用代理对象。
  • 具体主题类(RealSubject):也称为委托角色或者被代理角色。定义了代理对象所代表的指标对象。
  • 代理类(Proxy):也叫委托类、代理类。代理对象外部含有指标对象的援用,从而能够在任何时候操作指标对象;代理对象提供一个与指标对象雷同的接口,以便能够在任何时候代替指标对象。代理对象通常在客户端调用传递给指标对象之前或之后,执行某个操作,而不是单纯地将调用传递给指标对象。

代理模式实现

以下面的结构图为例,来看看代理模式的代码实现。

定义形象主题类(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();}
}

间接应用代理类,就能够实现预期的工作。

执行程序,打印日志如下:

 代理类 CarServiceProxy 选车:先增加一些日志
实在操作:选车
代理类 CarServiceProxy 品质检测:先增加一些日志
实在操作:品质检测 

能够看出,在实在的操作之前,能够通过代理类增加一些其余的操作。

Nacos 的代理模式实际

下面理解了代理模式的基本知识以及实例,上面就来看看 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 中对代理模式的使用算是比拟灵便,同时也并不是那么完满。这或者也提供了咱们对代理模式认知的另外一个视角。

如果文章内容有问题或想技术探讨请分割我(微信:zhuan2quan,备注 Nacos),如果感觉写的还不错,值得一起学习,那就关注一下吧。

Nacos 系列文章

  • 01《《跟二师兄学 Nacos 吧》第 1 篇 Nacos 客户端服务注册源码剖析》
  • EXT-01《《跟二师兄学 Nacos 吧》EXT-01 篇 看看 Nacos 是怎么活学活用简略工厂模式的!》
  • EXT-02《《跟二师兄学 Nacos 吧》EXT-02 篇 面试官问工厂模式,你了解的对吗?》
  • EXT-03《《跟二师兄学 Nacos 吧》EXT-03 篇 Nacos 中此处为什么采纳反射机制?》
  • EXT-04《《跟二师兄学 Nacos 吧》EXT-04 篇 Nacos 居然是这样应用代理模式的?》

博主简介:《SpringBoot 技术底细》技术图书作者,热爱钻研技术,写技术干货文章。

公众号:「程序新视界」,博主的公众号,欢送关注~

技术交换:请分割博主微信号:zhuan2quan

正文完
 0