<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 引用服務 dubbo中引用服務時,首先需要在配置文件使用`dubbo:reference`標簽引用接口,最主要的目的是指定引用的服務名;之后,在程序中使用Spring的Context的getBean()返回接口的代理實例;有了這個實例后就可以在Consumer端調用接口相關的方法。 `dubbo:reference`使用的ReferenceBean實現了FactoryBean接口,getBean時會調用getObject()方法,這是獲取引用的入口。 >FactoryBean:以Bean結尾,表示它是一個Bean,不同于普通Bean的是:它是實現了FactoryBean<T>接口的Bean,根據該Bean的Id從BeanFactory中獲取的實際上是FactoryBean的getObject()返回的對象,而不是FactoryBean本身, 如果要獲取FactoryBean對象,可以在id前面加一個&符號來獲取。 getObject首先會檢查是否已經獲取過,如果沒有獲取過才會執行init進行初始化。主要過程有: ![refer流程](http://www.uxiaowo.com/dubbo/refer.png) ## 1.檢查配置 獲取consumer端全局配置,檢查是否指定了interfaceName,檢查指定的接口類是否存在;可以配置一個屬性`dubbo.resolve.file`,指定一個文件或使用默認的文件`dubbo-resolve.properties`,內部可以配置將interfaceName轉換為url,這個url是點對點直連服務地址; 根據application>module>consumer依次獲取注冊中心,監控中心等信息,組裝成map。這個map中保存了服務及全局配置的信息,用于后續生成代理對象。 ## 2.創建invoker 引用服務時的invoker與發布服務時創建的invoker不同,發布服務中時為了在客戶端請求時服務器調用實現類,而引用服務時生成的invoker是為了封裝底層的序列化、通信等操作。 1. 將map轉為url,如果resolver中指定了url,那么不從injvm中引用;默認情況下如果本地有服務暴露,則引用本地服務;若為injvm協議則使用protocol的refer獲取invoker,具體的過程可見injvm實現。 ``` private static final Protocol refprotocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); invoker = refprotocol.refer(interfaceClass, url); ``` 2.如果不是injvm協議,會檢查是否提供了點對點直連地址,如果提供了則解析地址加入urls中;如果沒有提供則會加載注冊中心,獲取注冊中心的url 3.如果有一個直連地址或一個注冊中心,會使用這個地址創建invoker ``` invoker = refprotocol.refer(interfaceClass, urls.get(0)); ``` 4.如果有多個直連地址或多個注冊中心,則會遍歷地址,生成多個invoker加入到一個invoker列表,然后將該列表包裝為Directory對象,加入到Cluster中。 ``` List<Invoker<?>> invokers = new ArrayList<Invoker<?>>(); URL registryURL = null; for (URL url : urls) { invokers.add(refprotocol.refer(interfaceClass, url)); if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) { registryURL = url; // 用了最后一個registry url } } if (registryURL != null) { // 有 注冊中心協議的URL // 對有注冊中心的Cluster 只用 AvailableCluster URL u = registryURL.addParameter(Constants.CLUSTER_KEY, AvailableCluster.NAME); invoker = cluster.join(new StaticDirectory(u, invokers)); } else { // 不是 注冊中心的URL invoker = cluster.join(new StaticDirectory(invokers)); } ``` 在這里,需要對Directory對象和Cluster進行說明。 Directory接口保存了某個服務的Invoker列表 ``` public interface Directory<T> extends Node { Class<T> getInterface(); // 獲取接口類 List<Invoker<T>> list(Invocation invocation) throws RpcException; // 列出Invoker列表 } ``` Cluster接口的目的是存在多個服務提供者時,失敗自動切換,當出現失敗,重試其它服務器。通過觀察接口,我們可以看出,Cluster中的Directory保存Invoker列表,Cluster又封裝為一個Invoker,在doInvoker中做失敗切換的策略。 ``` public interface Cluster { <T> Invoker<T> join(Directory<T> directory) throws RpcException; } ``` ### 協議引用服務 1. 由于此時的url是`registry://`,會首先獲取 ``` |- ProtocolFilterWrapper |- ProtocolListenerWrapper |- RegistryProtocol ``` ProtocolFilterWrapper和ProtocolListenerWrapper在`registry://`時不起作用,會直接交給RegistryProtocol處理,RegistryProtocol內部首先獲取注冊中心,如果配置了group屬性則使用MergeableCluster,否則使用Cluster$Adaptive; 2.RegistryProtocol會創建RegistryDirectory保存invoker列表,首先通知注冊中心注冊要消費的服務;使用注冊中心的register()注冊`consumer://xxx/xxx?xxx`,在zookeeper上創建`/dubbo/接口名/consumers/consumer://xxx`節點。 3. 之后,使用RegistryDirectory的subscribe方法訂閱服務消費者`consumer://xxx/xxx?xxx`,根據url中category的值創建以下幾個節點,并添加監聽事件,監聽事件在RegistryDirectory中,也就是說如果providers、configurators、routers節點發生變化,RegistryDirectory會根據注冊中心的配置修改內部的Invoker列表 ``` [/dubbo/com.alibaba.dubbo.demo.DemoService/providers, /dubbo/com.alibaba.dubbo.demo.DemoService/configurators, /dubbo/com.alibaba.dubbo.demo.DemoService/routers] ``` 4. 最后使用`cluster.join(directory)`創建一個可以進行失敗重試的Invoker返回。 ## 3.創建代理 生成invoker后,最重要的一步時生成代理對象給應用程序使用,使用下面的程序生成指定接口的實例 ``` private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); (T) proxyFactory.getProxy(invoker); ``` proxyFactory對象與發布服務流程中一樣,也是下面的結構, ``` -| StubProxyFactoryWrapper -| JavassistProxyFactory ``` StubProxyFactoryWrapper的getProxy方法中使用內部的JavassistProxyFactory的getProxy方法,并對GenericService類型的接口進行處理。 JavassistProxyFactory的getProxy方法中會將consumer端生成的invoker實例包裝為指定的服務接口的實例,便于應用程序直接調用相關方法。 ``` public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) { return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker)); } ``` 首先使用 Proxy.getProxy()創建了interfaces接口的實現類A,newInstance方法會實例化這個實現類A并將invoker包裝為InvokerInvocationHandler傳給實現類的實例。 ``` Proxy.getProxy() 動態創建實現類A new A(new InvokerInvocationHandler(invoker)); ``` 在實現上,getProxy()會動態生成一個類A,內部包含了接口中定義的方法,內部會使用InvokerInvocationHandler執行相關邏輯 ``` // 動態創建實現類A的sayHello方法會執行handler的invoke方法 public abstract java.lang.String com.alibaba.dubbo.demo.DemoService.sayHello(java.lang.String){ Object[] args = new Object[1]; args[0] = ($w)$1; Object ret = handler.invoke(this, methods[0], args); return (java.lang.String)ret; } ``` 而InvokerInvocationHandler中執行invoker的invoke方法,由于不同協議生成的Invoker不同,會執行不同的調用。 ``` 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]); } return invoker.invoke(new RpcInvocation(method, args)).recreate(); } ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看