成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Dubbo服務(wù)消費(fèi)者調(diào)用過程

B0B0 / 2832人閱讀

摘要:先來說第種類型,即遠(yuǎn)程通信的,看的源碼,調(diào)用過程大致內(nèi)容就是將通過遠(yuǎn)程通信將信息傳遞給服務(wù)器端,服務(wù)器端接收到該信息后,找到對(duì)應(yīng)的本地,然后通過反射執(zhí)行相應(yīng)的方法,將方法的返回值再通過遠(yuǎn)程通信將結(jié)果傳遞給客戶端。

上圖是服務(wù)消費(fèi)的主過程:

首先通過ReferenceConfig類的private void init()方法會(huì)先檢查初始化所有的配置信息后,調(diào)用private T createProxy(Map map)創(chuàng)建代理,消費(fèi)者最終得到的是服務(wù)的代理, 在createProxy接著調(diào)用Protocol 接口實(shí)現(xiàn)的 Invoker refer(Class type, URL url)方法生成Invoker實(shí)例(如上圖中的紅色部分),這是服務(wù)消費(fèi)的關(guān)鍵。接下來把Invoker通過ProxyFactory代理工廠轉(zhuǎn)換為客戶端需要的接口(如:HelloWorld),創(chuàng)建服務(wù)代理并返回。

消費(fèi)端的初始化過程

1、把服務(wù)引用的信息封裝成URL并注冊(cè)到zk注冊(cè)中心;
2、監(jiān)聽注冊(cè)中心的服務(wù)的上下線;
3、連接服務(wù)提供端,創(chuàng)建NettyClient對(duì)象;
4、將這些信息包裝成DubboInvoker消費(fèi)端的調(diào)用鏈,創(chuàng)建消費(fèi)端Invoker實(shí)例的服務(wù)代理并返回;

消費(fèi)端的服務(wù)引用過程

1、經(jīng)過負(fù)載均衡策略,調(diào)用提供者;
2、選擇其中一個(gè)服務(wù)的URL與提供者netty建立連接,使用ProxyFactory 創(chuàng)建遠(yuǎn)程通信,或者本地通信的,Invoker發(fā)到netty服務(wù)端;
3、服務(wù)器端接收到該Invoker信息后,找到對(duì)應(yīng)的本地Invoker,處理Invocation請(qǐng)求;
4、獲取異步,或同步處理結(jié)果;

異步 不需要返回值:直接調(diào)用ExchangeClient.send()方法;

同步 需要返回值:使用ExchangeClient.request()方法,返回一個(gè)ResponseFuture,一直阻塞到服務(wù)端返回響應(yīng)結(jié)果;

案例介紹

先看一個(gè)簡(jiǎn)單的客戶端引用服務(wù)的例子,HelloServicedubbo配置如下:




使用Zookeeper作為注冊(cè)中心

引用遠(yuǎn)程的HelloService接口服務(wù)

根據(jù)之前的介紹,在Spring啟動(dòng)的時(shí)候,根據(jù)配置會(huì)創(chuàng)建一個(gè)ReferenceBean,該bean又實(shí)現(xiàn)了Spring的FactoryBean接口,所以我們?nèi)缦路绞绞褂脮r(shí):

@Autowired
private HelloService helloService;

使用的不是ReferenceBean對(duì)象,而是ReferenceBean的getObject()方法返回的對(duì)象,該對(duì)象通過代理實(shí)現(xiàn)了HelloService接口,所以要看服務(wù)引用的整個(gè)過程就需要從ReferenceBean.getObject()方法開始入手。

服務(wù)引用過程

將ReferenceConfig.init()中的內(nèi)容拆成具體的步驟,如下:

第一步:收集配置參數(shù)
methods=hello,
timestamp=1443695417847,
dubbo=2.5.3
application=consumer-of-helloService
side=consumer
pid=7748
interface=com.demo.dubbo.service.HelloService
第二步:從注冊(cè)中心獲取服務(wù)地址,返回Invoker對(duì)象

如果是單個(gè)注冊(cè)中心,代碼如下:

Protocol refprotocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

invoker = refprotocol.refer(interfaceClass, url);

上述url的內(nèi)容如下:

registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?
application=consumer-of-helloService&
dubbo=2.5.6&
pid=8292&
registry=zookeeper&
timestamp=1443707173909&

refer=
    application=consumer-of-helloService&
    dubbo=2.5.6&
    interface=com.demo.dubbo.service.HelloService&
    methods=hello&
    pid=8292&
    side=consumer&
    timestamp=1443707173884&
第三步:使用ProxyFactory創(chuàng)建出Invoker的代理對(duì)象
ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();

proxyFactory.getProxy(invoker);

下面就詳細(xì)說明下上述提到的幾個(gè)概念:Protocol、Invoker、ProxyFactory

概念介紹 Invoker

Invoker是一個(gè)可執(zhí)行對(duì)象,有三種類型的Invoker:

本地執(zhí)行的Invoker(服務(wù)端使用)

遠(yuǎn)程通信執(zhí)行的Invoker(客戶端使用)

多個(gè)類型2的Invoker聚合成的集群版Invoker(客戶端使用)

Invoker的實(shí)現(xiàn)情況如下:

先來看服務(wù)引用的第2個(gè)步驟,返回Invoker對(duì)象

對(duì)于客戶端來說,Invoker應(yīng)該是2、3這兩種類型。先來說第2種類型,即遠(yuǎn)程通信的Invoker,看DubboInvoker的源碼,調(diào)用過程AbstractInvoker.invoke()->doInvoke():

    protected Result doInvoke(final Invocation invocation) throws Throwable {
        RpcInvocation inv = (RpcInvocation) invocation;
        final String methodName = RpcUtils.getMethodName(invocation);
        inv.setAttachment(Constants.PATH_KEY, getUrl().getPath());
        inv.setAttachment(Constants.VERSION_KEY, version);

        ExchangeClient currentClient;
        if (clients.length == 1) {
            currentClient = clients[0];
        } else {
            currentClient = clients[index.getAndIncrement() % clients.length];
        }
        try {
            boolean isAsync = RpcUtils.isAsync(getUrl(), invocation);
            boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);
            int timeout = getUrl().getMethodParameter(methodName, Constants.TIMEOUT_KEY,Constants.DEFAULT_TIMEOUT);
            if (isOneway) {
                boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false);
                currentClient.send(inv, isSent);
                RpcContext.getContext().setFuture(null);
                return new RpcResult();
            } else if (isAsync) {
                ResponseFuture future = currentClient.request(inv, timeout) ;
                RpcContext.getContext().setFuture(new FutureAdapter(future));
                return new RpcResult();
            } else {
                RpcContext.getContext().setFuture(null);
                return (Result) currentClient.request(inv, timeout).get();
            }
        } catch (TimeoutException e) {
            throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
        } catch (RemotingException e) {
            throw new RpcException(RpcException.NETWORK_EXCEPTION, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
        }
    }

大致內(nèi)容就是:
將通過遠(yuǎn)程通信將Invocation信息傳遞給服務(wù)器端,服務(wù)器端接收到該Invocation信息后,找到對(duì)應(yīng)的本地Invoker,然后通過反射執(zhí)行相應(yīng)的方法,將方法的返回值再通過遠(yuǎn)程通信將結(jié)果傳遞給客戶端。

這里分3種情況:

執(zhí)行方法不需要返回值:直接調(diào)用ExchangeClient.send()方法。

執(zhí)行方法的結(jié)果需要異步返回:使用ExchangeClient.request()方法返回一個(gè)ResponseFuture對(duì)象,通過RpcContext中的ThreadLocal使ResponseFuture和當(dāng)前線程綁定,未等服務(wù)端響應(yīng)結(jié)果就直接返回,然后服務(wù)端通過ProtocolFilterWrapper.buildInvokerChain()方法會(huì)調(diào)用Filter.invoke()方法,即FutureFilter.invoker()->asyncCallback(),會(huì)獲取RpcContextResponseFuture對(duì)象,異步返回結(jié)果。

執(zhí)行方法的結(jié)果需要同步返回:使用ExchangeClient.request()方法,返回一個(gè)ResponseFuture,一直阻塞到服務(wù)端返回響應(yīng)結(jié)果

Protocol

服務(wù)引用的第二步就是:

Protocol refprotocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

invoker = refprotocol.refer(interfaceClass, url);

使用協(xié)議Protocol根據(jù)上述的url和服務(wù)接口來引用服務(wù),創(chuàng)建出一個(gè)Invoker對(duì)象

默認(rèn)實(shí)現(xiàn)的DubboProtocol也會(huì)經(jīng)過ProtocolFilterWrapper、ProtocolListenerWrapper、RegistryProtocol的包裝

首先看下RegistryProtocol.refer()方法,它干了哪些事呢?

將客戶端的信息注冊(cè)到注冊(cè)中心上

創(chuàng)建一個(gè)RegistryDirectory,從注冊(cè)中心中訂閱自己引用的服務(wù),將訂閱到的url在RegistryDirectory內(nèi)部轉(zhuǎn)換成Invoker。

RegistryDirectory是Directory的實(shí)現(xiàn),Directory代表多個(gè)Invoker,可以把它看成List類型的Invoker,但與List不同的是,它的值可能是動(dòng)態(tài)變化的,比如注冊(cè)中心推送變更RegistryDirectory內(nèi)部含有兩者重要屬性:

注冊(cè)中心服務(wù)Registry

Protocol 它會(huì)利用注冊(cè)中心服務(wù)Registry來獲取最新的服務(wù)器端注冊(cè)的url地址,然后再利用協(xié)議Protocol將這些url地址轉(zhuǎn)換成一個(gè)具有遠(yuǎn)程通信功能的Invoker對(duì)象,如DubboInvoker

在Directory的基礎(chǔ)上使用Cluster將上述多個(gè)Invoker對(duì)象聚合成一個(gè)集群版的Invoker對(duì)象

Directory和Cluster都是服務(wù)治理的重點(diǎn),接下去會(huì)多帶帶拿一章出來講

ProxyFactory

服務(wù)引用的第三步就是:

proxyFactory.getProxy(invoker);

對(duì)于Server端,ProxyFactory主要負(fù)責(zé)將服務(wù)如HelloServiceImpl統(tǒng)一進(jìn)行包裝成一個(gè)Invoker,這些Invoker通過反射來執(zhí)行具體的HelloServiceImpl對(duì)象的方法

對(duì)于client端,則是將上述創(chuàng)建的集群版Invoker(Cluster)創(chuàng)建出代理對(duì)象

代碼如下:

public class JavassistProxyFactory extends AbstractProxyFactory {

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

可以看到是利用jdk自帶的Proxy來動(dòng)態(tài)代理目標(biāo)對(duì)象Invoker,所以我們調(diào)用創(chuàng)建出來的代理對(duì)象如HelloService的方法時(shí),會(huì)執(zhí)行InvokerInvocationHandler中的邏輯:

public class InvokerInvocationHandler implements InvocationHandler {

    private final Invoker invoker;

    public InvokerInvocationHandler(Invoker handler){
        this.invoker = handler;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        Class[] parameterTypes = method.getParameterTypes();
        if (method.getDeclaringClass() == Object.class) {
            return method.invoke(invoker, args);
        }
        if ("toString".equals(methodName) && parameterTypes.length == 0) {
            return invoker.toString();
        }
        if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
            return invoker.hashCode();
        }
        if ("equals".equals(methodName) && parameterTypes.length == 1) {
            return invoker.equals(args[0]);
        }
        //AbstractClusterInvoker.invoke()
        return invoker.invoke(new RpcInvocation(method, args)).recreate();
    }

}

參考:http://dubbo.apache.org/books/dubbo-dev-book/implementation.html
參考:https://my.oschina.net/xiaominmin/blog/1599378

Contact

作者:鵬磊

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

版權(quán)歸作者所有,轉(zhuǎn)載請(qǐng)注明出處

Wechat:關(guān)注公眾號(hào),搜云庫(kù),專注于開發(fā)技術(shù)的研究與知識(shí)分享

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/71193.html

相關(guān)文章

  • 基于Dubbo+ZooKeeper的分布式服務(wù)的實(shí)現(xiàn)

    摘要:調(diào)用流程服務(wù)容器負(fù)責(zé)啟動(dòng),加載,運(yùn)行服務(wù)提供者。服務(wù)提供者在啟動(dòng)時(shí),向注冊(cè)中心注冊(cè)自己提供的服務(wù)。注冊(cè)中心返回服務(wù)提供者地址列表給消費(fèi)者,如果有變更,注冊(cè)中心將基于長(zhǎng)連接推送變更數(shù)據(jù)給消費(fèi)者。這就是分布式服務(wù)注冊(cè)中心的由來。 Dubbo是什么 一款分布式服務(wù)框架 高性能和透明化的RPC遠(yuǎn)程服務(wù)調(diào)用方案。這里簡(jiǎn)單介紹一下RPC,所謂RPC就是遠(yuǎn)程過程調(diào)用,全稱為Romate Proce...

    warkiz 評(píng)論0 收藏0
  • 基于Dubbo+ZooKeeper的分布式服務(wù)的實(shí)現(xiàn)

    摘要:調(diào)用流程服務(wù)容器負(fù)責(zé)啟動(dòng),加載,運(yùn)行服務(wù)提供者。服務(wù)提供者在啟動(dòng)時(shí),向注冊(cè)中心注冊(cè)自己提供的服務(wù)。注冊(cè)中心返回服務(wù)提供者地址列表給消費(fèi)者,如果有變更,注冊(cè)中心將基于長(zhǎng)連接推送變更數(shù)據(jù)給消費(fèi)者。這就是分布式服務(wù)注冊(cè)中心的由來。 Dubbo是什么 一款分布式服務(wù)框架 高性能和透明化的RPC遠(yuǎn)程服務(wù)調(diào)用方案。這里簡(jiǎn)單介紹一下RPC,所謂RPC就是遠(yuǎn)程過程調(diào)用,全稱為Romate Proce...

    enda 評(píng)論0 收藏0
  • Dubbo服務(wù)暴露過程

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

    bigdevil_s 評(píng)論0 收藏0
  • 構(gòu)建springmvc+myabtis+dubbo分布式平臺(tái)-dubbo簡(jiǎn)介

    摘要:服務(wù)自動(dòng)注冊(cè)與發(fā)現(xiàn),不再需要寫死服務(wù)提供方地址,注冊(cè)中心基于接口名查詢服務(wù)提供者的地址,并且能夠平滑添加或刪除服務(wù)提供者。調(diào)用關(guān)系說明服務(wù)容器負(fù)責(zé)啟動(dòng),加載,運(yùn)行服務(wù)提供者。服務(wù)提供者在啟動(dòng)時(shí),向注冊(cè)中心注冊(cè)自己提供的服務(wù)。 上一篇我們介紹《構(gòu)建dubbo分布式平臺(tái)-maven構(gòu)建ant-utils工具包的構(gòu)建》,從今天開始,我們進(jìn)入分布式服務(wù)項(xiàng)目的核心教程,真正使用dubbo實(shí)現(xiàn)分布...

    鄒立鵬 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

B0B0

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<