Dubbo源碼閱讀筆記1

来源:https://www.cnblogs.com/amwyyyy/archive/2018/01/25/8353504.html
-Advertisement-
Play Games

服務方初始化 服務方初始化的入口在ServiceConfig類的export方法 這裡的初始化是針對一個服務的 首先判斷是否要發佈,以及延遲發佈 先處理各種配置,按優先順序覆蓋 從配置中取註冊中心URL,註冊中心可能有多個 ...


### 服務方初始化

服務方初始化的入口在ServiceConfig類的export方法
這裡的初始化是針對一個服務的

public class ServiceConfig<T> extends AbstractServiceConfig {

    private static final long serialVersionUID = 3033787999037024738L;

    /** 
     * 獲取自適應擴展點
     * 自適應擴展點和普通擴展點的區別是:普通擴展點的實現類是確定的,自適應擴展點的實現類會根據參數不同變化
     * 這裡自適應擴展點用了位元組碼生成代理類來優化性能,使用動態代理應該也可以實現
     */
    private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
    
    // 代理工廠,用來生成代理類
    private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();

    // 保存隨機生成的埠號
    private static final Map<String, Integer> RANDOM_PORT_MAP = new HashMap<String, Integer>();

    // 延遲發佈的執行器
    private static final ScheduledExecutorService delayExportExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("DubboServiceDelayExporter", true));
    
    // 生成的服務發佈url
    private final List<URL> urls = new ArrayList<URL>();
    private final List<Exporter<?>> exporters = new ArrayList<Exporter<?>>();
    // 介面類型
    private String interfaceName;
    private Class<?> interfaceClass;
    // 介面實現類引用
    private T ref;
    // 服務名稱
    private String path;
    // 方法配置
    private List<MethodConfig> methods;
    private ProviderConfig provider;
    private transient volatile boolean exported;

    private transient volatile boolean unexported;

    // 是否泛化引用
    private volatile String generic;
    
    // ...
}

首先判斷是否要發佈,以及延遲發佈

public synchronized void export() {
    if (provider != null) {
        if (export == null) {
            export = provider.getExport();
        }
        if (delay == null) {
            delay = provider.getDelay();
        }
    }
    
    // 是否要發佈服務
    if (export != null && !export) {
        return;
    }

    // 延遲發佈配置
    if (delay != null && delay > 0) {
        delayExportExecutor.schedule(new Runnable() {
            public void run() {
                doExport();
            }
        }, delay, TimeUnit.MILLISECONDS);
    } else {
        doExport();
    }
}

先處理各種配置,按優先順序覆蓋

protected synchronized void doExport() {
    if (unexported) {
        throw new IllegalStateException("Already unexported!");
    }
    if (exported) {
        return;
    }
    exported = true;
    if (interfaceName == null || interfaceName.length() == 0) {
        throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!");
    }
    // 處理ProviderConfig
    checkDefault();

    // ...
    // 對配置各種處理
    // ...
    
    // 校驗配置
    checkApplication();
    checkRegistry();
    checkProtocol();

    // 最後處理ServiceConfig,優先順序最高
    appendProperties(this);
    
    checkStubAndMock(interfaceClass);
    if (path == null || path.length() == 0) {
        path = interfaceName;
    }
    
    // 發佈服務
    doExportUrls();
    
    // 把要服務提供者信息封裝成model,並設置方法可見性
    ProviderModel providerModel = new ProviderModel(getUniqueServiceName(), this, ref);
    // 放進全局的context中
    ApplicationModel.initProviderModel(getUniqueServiceName(), providerModel);
}

從配置中取註冊中心URL,註冊中心可能有多個

private void doExportUrls() {
    List<URL> registryURLs = loadRegistries(true);
    
    // 發佈到多種協議中
    for (ProtocolConfig protocolConfig : protocols) {
        doExportUrlsFor1Protocol(protocolConfig, registryURLs);
    }
}
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
    // ...
    // 將各種配置取出來放到map中,準備組裝成URL
    // ...
    
    // 根據優先順序取出配置的host和port
    String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
    Integer port = this.findConfigedPorts(protocolConfig, name, map);
    
    // 將所有參數封裝到URL對象中, 如: hessian://192.168.9.212:20880/com.alibaba.dubbo.demo.UserService?accesslog=true&anyhost=true&application=demo-provider&bind.ip=192.168.9.212&bind.port=20880&dispatcher=all&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.UserService&methods=getName&pid=20064&revision=1.0.0&side=provider&threadpool=cached&timeout=5000&timestamp=1513650421650&version=1.0.0
    URL url = new URL(name, host, port, (contextPath == null || contextPath.length() == 0 ? "" : contextPath + "/") + path, map);

    if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
            .hasExtension(url.getProtocol())) {
        url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
                .getExtension(url.getProtocol()).getConfigurator(url).configure(url);
    }

    String scope = url.getParameter(Constants.SCOPE_KEY);
    //配置為none不暴露
    if (!Constants.SCOPE_NONE.equalsIgnoreCase(scope)) {
        //配置不是remote的情況下做本地暴露 (配置為remote,則表示只暴露遠程服務)
        if (!Constants.SCOPE_REMOTE.equalsIgnoreCase(scope)) {
            exportLocal(url);
        }
        //如果配置不是local則暴露為遠程服務.(配置為local,則表示只暴露本地服務)
        if (!Constants.SCOPE_LOCAL.equalsIgnoreCase(scope)) {
            if (logger.isInfoEnabled()) {
                logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
            }
            if (registryURLs != null && registryURLs.size() > 0) {
                for (URL registryURL : registryURLs) {
                    url = url.addParameterIfAbsent("dynamic", registryURL.getParameter("dynamic"));
                    URL monitorUrl = loadMonitor(registryURL);
                    if (monitorUrl != null) {
                        url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString());
                    }
                    if (logger.isInfoEnabled()) {
                        logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
                    }
                    // 介面實現類生成動態代理的介面調用器,此調用器調用的是本地介面實現類,而消費方的調用器是調用遠程的方法。
                    // registryURL是註冊服務用的URL,url則是調用服務的url
                    Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
                    
                    // 包裝Invoker
                    DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

                    // 發佈服務方法
                    Exporter<?> exporter = protocol.export(wrapperInvoker);
                    exporters.add(exporter);
                }
            } else {
                // 沒有配置註冊中心時,直接發佈服務,服務只能通過直連方式引用
                
                Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
                DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

                Exporter<?> exporter = protocol.export(wrapperInvoker);
                exporters.add(exporter);
            }
        }
    }
    this.urls.add(url);
}

// 預設情況服務會發佈到遠程和本地,如果指定了local或remote則只發佈到本地或遠程
private void exportLocal(URL url) {
    // 將host設置成localhost,這樣只能本地調用了
    // 如果本身就指定了injvm則不用再次發佈到本地了。
    if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
        // injvm://127.0.0.1/com.alibaba.dubbo.demo.UserService?accesslog=true&anyhost=true&application=demo-provider&bind.ip=192.168.9.212&bind.port=20880&dispatcher=all&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.UserService&methods=getName&pid=20064&revision=1.0.0&side=provider&threadpool=cached&timeout=5000&timestamp=1513650421650&version=1.0.0
        URL local = URL.valueOf(url.toFullString())
                .setProtocol(Constants.LOCAL_PROTOCOL)
                .setHost(LOCALHOST)
                .setPort(0);
        
        // 暴露服務, 將介面實現類生成動態代理的介面調用器
        Exporter<?> exporter = protocol.export(
                proxyFactory.getInvoker(ref, (Class) interfaceClass, local));
        exporters.add(exporter);
        logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry");
    }
}

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 多註冊中心,一般用不到,但是某些情況下的確能解決不少問題,可以將某些dubbo服務註冊到2套dubbo系統中,實現服務在2套系統間的共用. 網上的配置說明很多,但包括dubbo官方說明文檔都是以xml文件配置方式舉例. 如想採用javaconfig的配置方式,則只需要對provider中的配置做適當 ...
  • session淺析 1.對於會話技術的理解 web會話技術包含Session和Cookie,會話技術是瀏覽器端與伺服器端的交互技術,拿cookie技術來說,客戶端在請求伺服器端的時候,如果有業務需要,伺服器會設置響應頭的key值與value值,在響應的時候帶給瀏覽器端,然後瀏覽器端在符合path條件 ...
  • 靜態頁面分為兩種,一種為jsp,另一種為html。 先看jsp的 在登陸的form表單中添加添加type為checkbox的input標簽 為該checkbox增加點擊事件 在後臺登錄方法中根據remember的值判斷是否設置Cookie 在頁面載入完後,獲取Cookie,並存入pageContex ...
  • import re # 正則表達式,用於提取數據 import requests # 下載網頁源代碼 ''' 安裝requests模塊:pip install requests 參考文檔:https://www.cnblogs.com/jamespan23/p/5526311.html ''' fo... ...
  • Logback介紹 Logback是由log4j創始人設計的又一個開源日誌組件。logback當前分成三個模塊:logback core,logback classic和logback access。logback core是其它兩個模塊的基礎模塊。logback classic是log4j的一個 ...
  • 擴展點載入(ExtensionLoader) 每一種類型的擴展點都有一個ExtensionLoader實例 1. 變數說明 2. 初始化 先從全局緩存裡面取,如果取不到則新建 ExtensionLoader構建方法,保存擴展點介面類型和對象工廠 擴展點對象工廠也是從通過ExtensionLoader ...
  • 消費方初始化 消費方初始化的入口在ReferenceConfig類的get方法 前面基本和服務方的初始化一致 創建代理類,代理遠程方法實現 ...
  • 1、bool值 這個貌似還可以理解,有比較運算符,邏輯運算符都是產生bool的值,先瞭解這幾個。中學數學題有這樣的真假(想起數學的痛)。 有一個int函數。百度解釋是取整的。先不去刻意瞭解,怕鑽進死衚衕。 2、if 看到判斷真假還有if,還真是一起數學題的一道題目。需要註意的就是老是直接寫數字,而不 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...