<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          《跟二師兄學(xué)Nacos吧》EXT-04篇 Nacos竟然是這樣使用代理模式的?

          共 8478字,需瀏覽 17分鐘

           ·

          2021-07-31 23:56

          學(xué)習(xí)不用那么功利,二師兄帶你從更高維度輕松閱讀源碼~

          隨著對Nacos源碼的深入閱讀,感覺越來越有意思了,大量的設(shè)計模式和基礎(chǔ)知識點(diǎn)都在其中被運(yùn)用。不論你是否閱讀源碼,都值得借鑒一下Nacos的運(yùn)用案例。

          今天這篇文章,給大家介紹一下Nacos Client中對代理模式的運(yùn)用。閱讀這篇文章,你可以不懂Nacos源碼,但能夠?qū)W到代理模式的運(yùn)用;如果你準(zhǔn)備閱讀Nacos源碼,不僅可以學(xué)到代理模式的案例,還可以更加深刻的感知到Nacos中的設(shè)計思想。

          代理模式簡介

          通俗的來講,代理模式就是讓別人(代理)幫忙做你并不關(guān)心的事,作用就相當(dāng)于日常生活中的中介。

          比如,日常生活中,你想買輛車,你可以直接去自己挑選、質(zhì)檢等,但這個過程會耗費(fèi)你大量的時間和精力。那么,此時你就可以找一個代理,來幫忙實(shí)現(xiàn)挑選、質(zhì)檢的事情。

          對于軟件設(shè)計來說,代理模式的定義為:代理模式給某一個對象提供一個代理對象,并由代理對象控制對原對象的引用。通俗的來講代理模式就是我們生活中常見的中介。

          代理模式的結(jié)構(gòu)

          在不使用代理模式時,我們大概是這樣使用一個接口:

          客戶端在使用CarService接口時需要創(chuàng)建CarServiceImpl類的實(shí)例,然后進(jìn)行業(yè)務(wù)邏輯處理。

          但在某些場景下,一個客戶類不想或者不能直接引用一個委托對象(CarServiceImpl),此時代理類對象可以在客戶類和委托對象之間起到中介的作用,并提供相同的功能。

          如果提供相同的功能,那么代理類和委托類就需要實(shí)現(xiàn)相同的接口。此時,上圖就演變成了代理模式:

          代理模式

          在代理模式的圖中,對比普通的直接使用,新增了代理類,并且代理類持有了委托類(真實(shí)對象)的引用。代理類本身并不真正實(shí)現(xiàn)服務(wù),而是通過調(diào)用委托類的相關(guān)方法,來提供特定的服務(wù),所以要持有真實(shí)類的引用。

          代理類可以在業(yè)務(wù)功能執(zhí)行的前后加入一些公共的服務(wù),比如負(fù)責(zé)為委托類預(yù)處理消息、過濾消息、把消息轉(zhuǎn)發(fā)給委托類,以及事后對返回結(jié)果的處理等。

          代理模式中的角色:

          • 抽象主題類(Subject):聲明了目標(biāo)對象和代理對象的共同接口,在任何可以使用目標(biāo)對象的地方都可以使用代理對象。
          • 具體主題類(RealSubject):也稱為委托角色或者被代理角色。定義了代理對象所代表的目標(biāo)對象。
          • 代理類(Proxy):也叫委托類、代理類。代理對象內(nèi)部含有目標(biāo)對象的引用,從而可以在任何時候操作目標(biāo)對象;代理對象提供一個與目標(biāo)對象相同的接口,以便可以在任何時候替代目標(biāo)對象。代理對象通常在客戶端調(diào)用傳遞給目標(biāo)對象之前或之后,執(zhí)行某個操作,而不是單純地將調(diào)用傳遞給目標(biāo)對象。

          代理模式實(shí)現(xiàn)

          以上面的結(jié)構(gòu)圖為例,來看看代理模式的代碼實(shí)現(xiàn)。

          定義抽象主題類(CarService)、具體主題類(CarServiceImpl)、代理類(CarServiceProxy):

          // 抽象主題類
          public interface CarService {
              // 選車
              Car chooseCar();
              // 質(zhì)量檢查
              boolean qualityCheck();
          }

          // 具體主題類
          public class CarServiceImpl implements CarService {
              @Override
              public Car chooseCar() {
                  System.out.println("真實(shí)操作:選車");
                  return new Car();
              }

              @Override
              public boolean qualityCheck() {
                  System.out.println("真實(shí)操作:質(zhì)量檢測");
                  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質(zhì)量檢測:先添加一些日志");
                  return real.qualityCheck();
              }
          }

          對應(yīng)的客戶端測試類:

          public class Client {

              public static void main(String[] args) {

                  CarService carService = new CarServiceProxy();
                  carService.chooseCar();
                  carService.qualityCheck();
              }
          }

          直接使用代理類,就可以完成預(yù)期的工作。

          執(zhí)行程序,打印日志如下:

          代理類CarServiceProxy選車:先添加一些日志
          真實(shí)操作:選車
          代理類CarServiceProxy質(zhì)量檢測:先添加一些日志
          真實(shí)操作:質(zhì)量檢測

          可以看出,在真實(shí)的操作之前,可以通過代理類添加一些其他的操作。

          Nacos的代理模式實(shí)踐

          上面了解了代理模式的基本知識以及實(shí)例,下面就來看看Nacos中是如何實(shí)現(xiàn)代理模式的。

          Nacos Client與注冊中心進(jìn)行通信采用了兩種通信協(xié)議:HTTP協(xié)議和gRPC協(xié)議。這兩個協(xié)議實(shí)現(xiàn)了共同的抽象主題類NamingClientProxy,具體主題類有NamingHttpClientProxy和NamingGrpcClientProxy,分別對應(yīng)Http協(xié)議和gRPC協(xié)議實(shí)現(xiàn)。

          此時,Nacos考慮到要支持通過配置來靈活選擇具體的通信協(xié)議,而這個功能呢又沒辦法讓這兩個具體的主題類來實(shí)現(xiàn),因此就產(chǎn)生了一個代理類NamingClientProxyDelegate來完成一些預(yù)先的處理和判斷。

          整個代理模式的使用類圖如下:

          代理模式

          通過上圖可以發(fā)現(xiàn),Nacos的代理模式使用與標(biāo)準(zhǔn)的代理模式還有一些區(qū)別。

          首先,NamingClientProxyDelegate同時代理了具體主題類,這可能考慮的是方便通信協(xié)議的配置切換。同時,在代理類中還處理了一些事件監(jiān)聽等額外功能。

          其次,說話Nacos這塊的命名并不友好,比如抽象主題直接以Proxy為后綴,容易讓人混淆。這就導(dǎo)致與代理模式中的代理類命名沖突,于是將代理類的后綴替換為了Delegate。

          上圖中的客戶類便是NacosNamingService,在其中實(shí)現(xiàn)了代理類的初始化操作,具體代碼實(shí)現(xiàn)如下:

          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部分實(shí)現(xiàn)如下:

          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);
              }
            // ...
          }

          可以看出,代理類實(shí)現(xiàn)了NamingClientProxy接口,同時持有了NamingHttpClientProxy和NamingGrpcClientProxy的對象引用,并且對它們進(jìn)行了初始化操作。

          關(guān)于NamingHttpClientProxy和NamingGrpcClientProxy的代碼我們就不再展示,它們首先繼承了AbstractNamingClientProxy抽象類,該抽象類實(shí)現(xiàn)NamingClientProxy接口。

          從整體上來說,Nacos中對代理模式的運(yùn)用還是比較靈的,結(jié)合場景一個代理類代理了兩個具體實(shí)現(xiàn)類,但同時在命名方面的問題,還有待商榷。

          代理模式和裝飾器模式的區(qū)別

          在學(xué)習(xí)使用代理模式時,經(jīng)常會有朋友與裝飾器模式相混淆。這里就簡單聊一下它們直接的區(qū)別。

          裝飾器模式中,裝飾者(decorator)和被裝飾者(decoratee)都實(shí)現(xiàn)同一個接口。代理模式中,代理類(proxy class)和真實(shí)處理的類(real class)都實(shí)現(xiàn)同一個接口。而且兩者都對類的方法進(jìn)行擴(kuò)展,看起來邊界的確比較模糊。

          但還是有一些區(qū)別點(diǎn)的:

          • 裝飾器模式強(qiáng)調(diào)的是增強(qiáng)自身,比如增加之后可提供更多的屬性和方法;代理模式強(qiáng)調(diào)要讓別人幫你去做一些本身與你業(yè)務(wù)沒有太多關(guān)系的職責(zé)(記錄日志、設(shè)置緩存)。代理模式是為了實(shí)現(xiàn)對象的控制,因?yàn)楸淮淼膶ο笸y以直接獲得或者是其內(nèi)部不想暴露出來。
          • 裝飾模式是以對客戶端透明的方式擴(kuò)展對象的功能,是繼承方案的一個替代方案;代理模式則是給一個對象提供一個代理對象,并由代理對象來控制對原有對象的引用;
          • 裝飾模式是為裝飾的對象增強(qiáng)功能;而代理模式對代理的對象施加控制,但不對對象本身的功能進(jìn)行增強(qiáng);

          小結(jié)

          代理模式在日常業(yè)務(wù)代碼中還是比較少見的,本文我們重點(diǎn)介紹了靜態(tài)代理模式及在Nacos中的運(yùn)用。關(guān)于動態(tài)代理,在Spring的框架中可以看到很多實(shí)例,有機(jī)會我們再進(jìn)行講解。而Nacos中對代理模式的運(yùn)用算是比較靈活,同時也并不是那么完美。這或許也提供了我們對代理模式認(rèn)知的另外一個視角。


          往期推薦

          Int(4)和Int(11) 你選的是哪個?

          使用了synchronized,竟然還有線程安全問題!

          《跟二師兄學(xué)Nacos吧》EXT-03篇 Nacos中此處為什么采用反射機(jī)制?

          《跟二師兄學(xué)Nacos吧》EXT-02篇 面試官問工廠模式,你理解的對嗎?

          《跟二師兄學(xué)Nacos吧》EXT-01篇 看看Nacos是怎么活學(xué)活用簡單工廠模式的!




          如果你覺得這篇文章不錯,那么,下篇通常會更好。添加微信好友,可備注“加群”(微信號:zhuan2quan)。

          一篇文章就看透技術(shù)本質(zhì)的人,
            和花一輩子都看不清的人,
            注定是截然不同的搬磚生涯。
          ▲ 按關(guān)注”程序新視界“,洞察技術(shù)內(nèi)幕
          瀏覽 43
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  91免费三级片网站 | 国家一级A片 | 操逼视频五月天 | 大香蕉国产精品视频 | 免费看黃色AAAAAA片 |