<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之旅 廣告
                # 發布服務 在Spring的ClassPathXmlApplicationContext初始化結束后,會觸發ApplicationEvent事件;dubbo使用`<dubbo:service>`發布服務,該標簽對應的是ServiceBean,這個類實現了ApplicationListener接口,并在ContextRefreshedEvent事件時調用export()發布服務。 ![服務發布流程](http://www.uxiaowo.com/dubbo/export.png) ## 1.檢查配置 1.export()中會判斷是否需要發布,如果provider的export為false則不發布;還會判斷是否需要延遲發布,如果需要則加入到線程池中延遲執行,否則立即執行。 2.發布前檢查,如果已經發布或取消發布,則結束;如果未設置interface則拋出異常;從provider中獲取application應用、module模塊、registries注冊中心、monitor監控中心、protocols協議等信息;若模塊不為空,則從模塊中獲取registries注冊中心和monitor監控中心;若application應用不為空,那則從應用中獲取registries注冊中心和monitor監控中心; 3.設置并加載interface指定的class,即檢查class存在并且為接口類型;檢查ref引用的實現類不為空并且是interfaceClass的實現類。 4.如果設置了local和stub,檢查class是否存在;stub在客戶端設置,stub的構造方法引用了遠程接口,用于想在客戶端也執行部分邏輯。 5.檢查application應用、registry注冊中心和protocol協議、server的相關環境配置, 6.調用doExportUrls發布服務的url ## 2.根據注冊中心配置信息生成url 1. 檢查`<dubbo:registry>`,如果未設置,從`dubbo.registry.address`獲取,如果還沒有找到注冊中心的配置則拋出異常。最后,從系統配置中獲取參數修改注冊中心的配置。 2. 遍歷注冊中心,將注冊中心轉為url的形式,一個provider可能有多個注冊中心,一個注冊中心的配置中可能有多個地址;例如: ``` <dubbo:application name="demo-provider"/> <dubbo:registry address="multicast://224.5.6.7:1234"/> 轉為: multicast://224.5.6.7:1234/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.0&pid=17690&timestamp=1511357579872 ``` 最后,修改協議為registry,原先的協議放在參數registry的值中,最后我們獲取了多個注冊中心的url,如: ``` registry://224.5.6.7:1234/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.0&pid=753&registry=multicast&timestamp=1511362038080 ``` ## 3. 發布服務 遍歷配置的協議,將服務發布到注冊中心,配置文件中可能配置了多個協議,每個服務針對多個協議會生成對應的多個服務url,內部包含了服務信息。 1.生成服務對應協議的url,先獲取ip和port,provider注冊&監聽ip地址,注冊與監聽ip可獨立配置 配置優先級:系統環境變量 -> java命令參數-D -> 配置文件host屬性 -> /etc/hosts中hostname-ip映射關系 -> 默認聯通注冊中心地址的網卡地址 -> 第一個可用的網卡地址;provider注冊&監聽端口,注冊與監聽port可獨立配置 配置優先級:啟動環境變量 -> java命令參數-D -> protocol配置文件port屬性配置 -> 協議默認端口 ``` <dubbo:protocol name="dubbo" port="20880"/> DemoService服務生成dubbo協議的url dubbo://192.168.1.30:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&bind.ip=192.168.1.30&bind.port=20880&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=17690&side=provider&timestamp=1511357867209 ``` 2. 查找ConfiguratorFactory的實現類,可以配置修改協議的url 3. scope為none時不暴露服務,scope為remote時,只發布到遠程,為local時,只發布到本地 ### 3.1 生成Invoker Invoker是一個調用器,主要的功能是客戶端請求服務時,服務端會查找發布服務時生成的Invoker方法,根據Invocation對象指定的方法和參數,執行其doInvoke方法,并將結果包裝為Result對象返回給客戶端,從而實現遠程調用。我們先來看一個示例, ``` //1. 創建了一個invoker實例,內部會調用DemoService的實現類的sayHello方法,并講結果包裝為Result對象。 Invoker<DemoService> invoker = new AbstractInvoker(DemoService.class,new URL("DUBBO", "127.0.0.1", 28001)) { @Override protected Result doInvoke(Invocation invocation) throws Throwable { DemoServiceImpl impl = new DemoServiceImpl(); return new RpcResult(impl.sayHello((String)invocation.getArguments()[0])); } }; // 2. 調用器根據Invocation指定的方法和參數調用實現類并返回結果 Result result = invoker.invoke(new RpcInvocation("sayHello", new Class[] {String.class}, new Object[] {"World!"})); System.out.println(result.getValue()); // 輸出為:Hello World! ``` 上面的例子中,將DemoService的實現類封裝成為了一個Invoker類,內部可以根據方法名執行不同的方法,為了便于演示,寫死了調用sayHello方法。 在dubbo中,使用下面的方法來創建Invoker實例,具體的代碼在ServiceConfig.java中。 ``` private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString())); ``` dubbo使用proxyFactory的getInvoker生成Invoker實例。我們先來討論一下proxyFactory,根據ExtensionLoader的實現,proxyFactory獲取Adaptive類時,首先找@Adaptive注解的類,如果沒有會由dubbo創建一個新的類ProxyFactory$Adaptive,其內部會根據url的proxy值獲取factory,默認取proxyFactor接口上的注解`@SPI("javassist")`指定的值,getExtension()時會根據傳入的參數獲取對應的ProxyFactory實現類,還會查找ProxyFactory實現類中將proxyFactory作為唯一參數的構造函數的實現類作為Wrapper類進行包裝。 ``` // ProxyFactory$Adaptive類 public com.alibaba.dubbo.rpc.Invoker getInvoker(java.lang.Object arg0, java.lang.Class arg1, com.alibaba.dubbo.common.URL arg2) throws com.alibaba.dubbo.rpc.RpcException { if (arg2 == null) throw new IllegalArgumentException("url == null"); com.alibaba.dubbo.common.URL url = arg2; String extName = url.getParameter("proxy", "javassist"); // 默認是javassist if (extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.ProxyFactory) from url(" + url.toString() + ") use keys([proxy])"); com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory) ExtensionLoader .getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension(extName); return extension.getInvoker(arg0, arg1, arg2); } ``` 對ProxyFactory接口來說,最終生成的類是StubProxyFactoryWrapper,內部的proxyFactory為JavassistProxyFactory。proxyFactory變量的對象鏈如下: ``` -| StubProxyFactoryWrapper -| JavassistProxyFactory ``` StubProxyFactoryWrapper的getInvoker方法會調用內部JavassistProxyFactory的getInvoker ``` // JavassistProxyFactory public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) { // TODO Wrapper類不能正確處理帶$的類名 final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type); return new AbstractProxyInvoker<T>(proxy, type, url) { @Override protected Object doInvoke(T proxy, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable { return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments); } }; } ``` JavassistProxyFactory內部邏輯,首先使用`Wrapper.getWrapper`將指定的ref類包裝為Wrapper類,Wrapper類內部包含`invokeMethod(Object instance, String mn, Class<?>[] types, Object[] args)`可以調用指定實例的某個方法。最后將Wrapper包裝為一個AbstractProxyInvoker類。Wrapper類動態生成,內部會直接調用實現類的方法,而不是使用反射調用,下面是invokeMethod的實現。 ``` public Object invokeMethod(Object o, String n, Class[] p, Object[] v){ com.alibaba.dubbo.demo.provider.DemoServiceImpl w; try{ w = ((com.alibaba.dubbo.demo.provider.DemoServiceImpl)$1); }catch(Throwable e){ throw new IllegalArgumentException(e); } try{ if( "sayHello".equals( $2 ) && $3.length == 1 ) { return ($w)w.sayHello((java.lang.String)$4[0]); } } catch(Throwable e) { throw new java.lang.reflect.InvocationTargetException(e); } } ``` 經過這一系列的過程,我們完成了Invoker對象的創建,下面是內部調用結構: ``` |-AbstractProxyInvoker:invoker() |-Wrapper:invokeMethod() |-DemoService : 指定的方法 ``` ### 3.2 發布Invoker 由于不同協議發布的方式不同,因此根據dubbo的理念,會根據url加載不同的protocol實現類來發布AbstractProxyInvoker的實例。與ProxyFactory類似,ExtensionLoader加載Protocol后的protocol實例為: ``` |- ProtocolFilterWrapper |- ProtocolListenerWrapper |- RegistryProtocol ``` ProtocolFilterWrapper和ProtocolListenerWrapper在發布registry協議時,不會添加監聽類和調用鏈,而是直接調用內部Protocol的export方法,最終會調用RegistryProtocol的export方法。 1. 根據配置的協議發布ref實現類的Invoker:在配置文件中,我們可能定義了多個類似`<dubbo:protocol name="dubbo" port="20880"/>`的協議,這里的目的就是將服務發布到各個協議中,與injvm協議類似,會根據url的協議使用不同的Protocol實現類,并被ProtocolFilterWrapper和ProtocolListenerWrapper包裝為協議鏈。后續對dubbo進行詳細說明。 2. 根據注冊中心的協議創建注冊中心 3. 將服務注冊到注冊中心 4. 向服務中心訂閱服務,訂閱時會添加監聽類 5. 返回一個Exporter,用于獲取服務信息,取消服務 由于每個注冊中心的實現不同,因此只做主要的流程說明,后續會對zookeeper注冊中心的實現進行說明,對injvm、dubbo協議進行說明。
                  <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>

                              哎呀哎呀视频在线观看