国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Dubbo服務提供者發布過程

lifesimple / 1787人閱讀

摘要:將標記為服務,使用對象來提供具體的服務。這整個過程算是該類的典型的執行過程。從上面得知服務發布的第一二個過程獲取注冊中心信息和協議信息。對于端來說,上述服務發布的第步中要解決的問題是根據指定協議向注冊中心注冊服務。

上圖是服務提供者暴露服務的主過程

首先ServiceConfig類拿到對外提供服務的實際類ref(如:HelloServiceImpl),然后通過ProxyFactory類的getInvoker方法使用ref生成一個AbstractProxyInvoker實例,到這一步就完成具體服務到Invoker的轉化。接下來就是Invoker轉換到Exporter的過程。

Dubbo處理服務暴露的關鍵就在Invoker轉換到Exporter的過程(如上圖中的紅色部分),Dubbo協議的Invoker轉為Exporter發生在DubboProtocol類的export方法,它主要是打開socket偵聽服務,并接收客戶端發來的各種請求,通訊細節由Dubbo自己實現.

服務發布過程大致分成3步

1、獲取注冊中心信息,構建協議信息,然后將其組合。
2、通過ProxyFactory將HelloServiceImpl封裝成一個Invoker執行 。
3、使用Protocol將invoker導出成一個Exporter(包括去注冊中心注冊服務等)。

這里面就涉及到幾個大的概念,ProxyFactory、Invoker、Protocol、Exporter

Export 服務暴露的步驟

1、首先會檢查各種配置信息 等標簽的配置,填充各種屬性,總之就是保證我在開始暴露服務之前,所有的東西都準備好了,并且是正確的。
2、加載所有的注冊中心,因為我們暴露服務需要注冊到注冊中心中去。
3、根據配置的所有協議和注冊中心url分別進行導出。
4、進行導出的時候,又是一波屬性的獲取設置檢查等操作。
5、如果配置的不是remote,則做本地導出。
6、如果配置的不是local,則暴露為遠程服務。
7、不管是本地還是遠程服務暴露,首先都會獲取Invoker。
8、獲取完Invoker之后,轉換成對外的Exporter,緩存起來。
9、執行DubboProtocol類的export方法,打開socket偵聽服務,并接收客戶端發來的各種請求。

概念介紹

先看一個簡單的服務端例子,dubbo配置如下:





有一個服務接口HelloService,以及它對應的實現類HelloServiceImpl。

將HelloService標記為dubbo服務,使用HelloServiceImpl對象來提供具體的服務。

使用zooKeeper作為注冊中心。

Invoker

Invoker,一個可執行對象,能夠根據方法名稱、參數得到相應的執行結果。接口如下:

public interface Invoker {

    Class getInterface();

    URL getUrl();

    Result invoke(Invocation invocation) throws RpcException;

    void destroy();

}

而Invocation則包含了需要執行的方法、參數等信息,接口如下:

public interface Invocation {

    URL getUrl();

    String getMethodName();

    Class[] getParameterTypes();

    Object[] getArguments();

}

目前其實現類只有一個RpcInvocation

Invoker這個可執行對象的執行過程分成三種類型:

本地執行的Invoker

遠程通信執行的Invoker

多個類型2的Invoker聚合成的集群版Invoker

以HelloService接口為例:

本地執行的Invokerserver端,含有對應的HelloServiceImpl實現,要執行該接口方法,僅僅只需要通過反射執行HelloServiceImpl對應的方法即可。

遠程通信執行的Invokerclient端,要想執行該接口方法,需要需要進行遠程通信,發送要執行的參數信息給server端;server端,利用上述本地執行的Invoker執行相應的方法,然后將返回的結果發送給client端。這整個過程算是該類Invoker的典型的執行過程。

集群版的Invokerclient端,擁有某個服務的多個Invoker,此時client端需要做的就是將多個Invoker聚合成一個集群版的Invoker,client端使用的時候,僅僅通過集群版的Invoker來進行操作。集群版的Invoker會從眾多的遠程通信類型的Invoker中選擇一個來執行(從中加入負載均衡、服務降級等策略),類似服務治理,dubbo已經實現了、

看下Invoker的實現情況:

ProxyFactory

對于Server端,主要負責將服務如HelloServiceImpl統一進行包裝成一個Invoker,通過反射來執行具體的HelloServiceImpl對象的方法

接口定義如下:

@SPI("javassist")
public interface ProxyFactory {

     //針對client端,創建出代理對象
    @Adaptive({Constants.PROXY_KEY})
     T getProxy(Invoker invoker) throws RpcException;

    //針對server端,將服務對象如HelloServiceImpl包裝成一個Invoker對象
    @Adaptive({Constants.PROXY_KEY})
     Invoker getInvoker(T proxy, Class type, URL url) throws RpcException;

}

ProxyFactory的接口實現有JdkProxyFactory、JavassistProxyFactory,默認是JavassistProxyFactory, JavassistProxyFactory內容如下:

public class JavassistProxyFactory extends AbstractProxyFactory {

    @SuppressWarnings("unchecked")
    public  T getProxy(Invoker invoker, Class[] interfaces) {
        return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
    }

    public  Invoker getInvoker(T proxy, Class type, URL url) {
        // TODO Wrapper類不能正確處理帶$的類名
        final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf("$") < 0 ? proxy.getClass() : type);
        return new AbstractProxyInvoker(proxy, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName, 
                                      Class[] parameterTypes, 
                                      Object[] arguments) throws Throwable {
                return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
            }
        };
    }

}

可以看到創建了一個AbstractProxyInvoker(這類就是本地執行的Invoker),AbstractProxyInvoker對invoke()方法的實現如下:

public Result invoke(Invocation invocation) throws RpcException {
    try {
        return new RpcResult(doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()));
    } catch (InvocationTargetException e) {
        return new RpcResult(e.getTargetException());
    } catch (Throwable e) {
        throw new RpcException("Failed to invoke remote proxy method " + invocation.getMethodName() + " to " + getUrl() + ", cause: " + e.getMessage(), e);
    }
}

綜上所述,服務發布的第二個過程就是:使用ProxyFactory將HelloServiceImpl封裝成一個本地執行的Invoker。

Protocol

從上面得知服務發布的第一、二個過程:

1、獲取注冊中心信息dubbo:registry和協議信息dubbo:protocol。
2、使用ProxyFactory將HelloServiceImpl封裝成一個本地執行的Invoker。

執行這個服務->執行這個本地的Invoker->調用AbstractProxyInvoker.invoke(Invocation invocation)方法,方法的執行過程就是通過反射執行HelloServiceImpl。

現在的問題是:客戶端如何調用服務端的方法(服務注冊到注冊中心->客戶端向注冊中心訂閱服務->客戶端調用服務端的方法)和上述Invocation參數的來源問題

對于Server端來說,上述服務發布的第3步中Protocol要解決的問題是:

根據指定協議向注冊中心注冊HelloService服務。

當客戶端根據協議調用這個服務時,將客戶端傳遞過來的Invocation參數交給上述的Invoker來執行。

所以Protocol會加入遠程通信這塊,根據客戶端的請求來獲取參數Invocation。

先來看下Protocol接口的定義:

@SPI("dubbo")
public interface Protocol {

    int getDefaultPort();

    //針對server端來說,將本地執行類的Invoker通過協議暴漏給外部。這樣外部就可以通過協議發送執行參數Invocation,然后交給本地Invoker來執行
    @Adaptive
     Exporter export(Invoker invoker) throws RpcException;

    //這個是針對客戶端的,客戶端從注冊中心獲取服務器端發布的服務信息
    //通過服務信息得知服務器端使用的協議,然后客戶端仍然使用該協議構造一個Invoker。這個Invoker是遠程通信類的Invoker。
    //執行時,需要將執行信息通過指定協議發送給服務器端,服務器端接收到參數Invocation,然后交給服務器端的本地Invoker來執行
    @Adaptive
     Invoker refer(Class type, URL url) throws RpcException;

    void destroy();

}

我們再來詳細看看服務發布的第3步(ServiceConfig):

Exporter exporter = protocol.export(invoker);

protocol的來歷是:

Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException{
    if (arg0 == null) {
        throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null"); 
    }
    if (arg0.getUrl() == null) {
        throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");
    }
    com.alibaba.dubbo.common.URL url = arg0.getUrl();
    String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
    if(extName == null) {
        throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])"); 
    }
    com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)com.alibaba.dubbo.common.ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
    return extension.export(arg0);
}

public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0,com.alibaba.dubbo.common.URL arg1) throws com.alibaba.dubbo.rpc.RpcException{
    if (arg1 == null) { 
        throw new IllegalArgumentException("url == null"); 
    }
    com.alibaba.dubbo.common.URL url = arg1;
    String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
    if(extName == null) {
        throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])"); 
    }
    com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)com.alibaba.dubbo.common.ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
    return extension.refer(arg0, arg1);
}

export(Invoker invoker)的過程即根據Invoker中url的信息來最終選擇Protocol的實現,默認實現是DubboProtocol,然后再對DubboProtocol進行依賴注入,進行wrap包裝(getExtension()方法)。

Protocol的實現情況:

可以看到在返回DubboProtocol之前,經過了ProtocolFilterWrapper、ProtocolListenerWrapper、RegistryProtocol的包裝

所謂包裝就是如下內容:

package com.alibaba.xxx;

import com.alibaba.dubbo.rpc.Protocol;

public class XxxProtocolWrapper implemenets Protocol {
    Protocol impl;

    public XxxProtocol(Protocol protocol) { impl = protocol; }

    // 接口方法做一個操作后,再調用extension的方法
    public Exporter export(final Invoker invoker) {
        //... 一些操作
        impl .export(invoker);
        // ... 一些操作
    }

    // ...
}

使用裝飾器模式,類似AOP的功能

下面主要講解RegistryProtocol和DubboProtocol,先暫時忽略ProtocolFilterWrapper、ProtocolListenerWrapper

RegistryProtocol.export() 主要功能是將服務注冊到注冊中心

DubboProtocol.export() 服務導出功能:

創建一個DubboExporter,封裝Invoker。

根據Invoker的url獲取ExchangeServer通信對象(負責與客戶端的通信模塊)。

現在我們搞清楚我們的目的,通過通信對象獲取客戶端傳來的Invocation參數,然后找到對應的DubboExporter(即能夠獲取到本地Invoker)就可以執行服務了。

在DubboProtocol中,每個ExchangeServer通信對象都綁定了一個ExchangeHandler對象,內容如下:

private ExchangeHandler requestHandler = new ExchangeHandlerAdapter() {

    public Object reply(ExchangeChannel channel, Object message) throws RemotingException {
        if (message instanceof Invocation) {
            Invocation inv = (Invocation) message;
            Invoker invoker = getInvoker(channel, inv);
            RpcContext.getContext().setRemoteAddress(channel.getRemoteAddress());
            ......
            return invoker.invoke(inv);
        }
        throw new RemotingException(channel, "Unsupported request: " + message == null ? null : (message.getClass().getName() + ": " + message) + ", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress());
    }
};

可以看到該類才是真正與客戶端通信,在獲取到Invocation參數后,調用getInvoker()來獲取本地的Invoker(先從exporterMap中獲取Exporter),就可以調用服務了。

而對于通信這塊,接下來會專門來詳細的說明,從reply參數可知,重點在了解ExchangeChannel

Exporter

負責維護invoker的生命周期,包含一個Invoker對象,接口定義如下:

public interface Exporter {

    Invoker getInvoker();

    void unexport();

}
結束語

以上就是本文簡略地介紹了及服務發布過程中的幾個 ProxyFactory、Invoker、Protocol、Exporter 概念

參考:http://dubbo.apache.org/books/dubbo-dev-book/implementation.html
參考:https://blog.csdn.net/qq418517226/article/details/51818769

Contact

作者:鵬磊

出處:http://www.ymq.io/2018/06/13/dubbo_rpc_export

版權歸作者所有,轉載請注明出處

Wechat:關注公眾號,搜云庫,專注于開發技術的研究與知識分享

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/71184.html

相關文章

  • Dubbo 一篇文章就夠了:從入門到實戰

    摘要:啟動容器,加載,運行服務提供者。服務提供者在啟動時,在注冊中心發布注冊自己提供的服務。注冊中心返回服務提供者地址列表給消費者,如果有變更,注冊中心將基于長連接推送變更數據給消費者。 一 為什么需要 dubbo 很多時候,其實我們使用這個技術的時候,可能都是因為項目需要,所以,我們就用了,但是,至于為什么我們需要用到這個技術,可能自身并不是很了解的,但是,其實了解技術的來由及背景知識,對...

    tomener 評論0 收藏0
  • Dubbo服務暴露過程

    摘要:根據的值,進行服務暴露。如果配置為則不暴露,如果服務未配置成,則本地暴露如果未配置成,則暴露遠程服務。提供者向注冊中心訂閱所有注冊服務當注冊中心有此服務的覆蓋配置注冊進來時,推送消息給提供者,重新暴露服務,這由管理頁面完成。 概覽 dubbo暴露服務有兩種情況,一種是設置了延遲暴露(比如delay=5000),另外一種是沒有設置延遲暴露或者延遲設置為-1(delay=-1): 設置了...

    bigdevil_s 評論0 收藏0
  • Dubbo 2.7.1 踩坑記

    摘要:面試題服務提供者能實現失效踢出是什么原理高頻題服務宕機的時候,該節點由于是持久節點會永遠存在,而且當服務再次重啟的時候會將重新注冊一個新節點。 Dubbo 2.7 版本增加新特性,新系統開始使用 Dubbo 2.7.1 嘗鮮新功能。使用過程中不慎踩到這個版本的 Bug。 系統架構 Spring Boot 2.14-Release + Dubbo 2.7.1 現象 Dubbo 服務者啟動...

    wudengzan 評論0 收藏0
  • 網關實現灰度發布

    摘要:就是一種灰度發布方式,讓一部分用戶繼續用,一部分用戶開始用,如果用戶對沒有什么反對意見,那么逐步擴大范圍,把所有用戶都遷移到上面來。灰度發布可以保證整體系統的穩定,在初始灰度的時候就可以發現調整問題,以保證其影響度。 一、背景互聯網產品開發有個非常特別的地方,就是不停的升級,升級,再升級。采用敏捷開發的方式,基本上保持每周或者每兩周一次的發布頻率,系統升級總是伴隨著各種風險,新舊版本兼...

    stormjun 評論0 收藏0

發表評論

0條評論

lifesimple

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<