1. 程式人生 > >Dubbo原理和原始碼解析之標籤解析

Dubbo原理和原始碼解析之標籤解析

github新增倉庫 "dubbo-read"(點此檢視),集合所有《Dubbo原理和原始碼解析》系列文章,後續將繼續補充該系列,同時將針對Dubbo所做的功能擴充套件也進行分享。不定期更新,歡迎Follow。

一、Dubbo 配置方式

Dubbo 支援多種配置方式:

  • XML 配置:基於 Spring 的 Schema 和 XML 擴充套件機制實現
  • 屬性配置:載入 classpath 根目錄下的 dubbo.properties
  • API 配置:通過硬編碼方式配置(不推薦使用)
  • 註解配置:通過註解方式配置(Dubbo-2.5.7及以上版本支援,不推薦使用)

對於 屬性配置

方式,可以通過環境變數、-D 啟動引數來指定 dubbo.properties 檔案,載入檔案順序為:

    1. -D 啟動引數
    2. 環境變數
    3. classpath 根目錄

載入程式碼如下:

public static final String DUBBO_PROPERTIES_KEY = "dubbo.properties.file";
public static final String DEFAULT_DUBBO_PROPERTIES = "dubbo.properties";

private static volatile Properties PROPERTIES;

public static Properties getProperties() { if (PROPERTIES == null) { synchronized (ConfigUtils.class) { if (PROPERTIES == null) { String path = System.getProperty(Constants.DUBBO_PROPERTIES_KEY); if (path == null || path.length() == 0) { path
= System.getenv(Constants.DUBBO_PROPERTIES_KEY); if (path == null || path.length() == 0) { path = Constants.DEFAULT_DUBBO_PROPERTIES; } } PROPERTIES = ConfigUtils.loadProperties(path, false, true); } } } return PROPERTIES; }

本文主要分析 XML 配置的實現原理和原始碼,其他方式不予贅述。

二、XML 配置

文章開頭已經提到,XML 配置方式是基於 Spring 的 Schema 和 XML 擴充套件機制實現的。通過該機制,我們可以編寫自己的 Schema,並根據自定義的 Schema 自定義標籤來配置 Bean。

使用 Spring 的 XML 擴充套件機制有以下幾個步驟:

    1. 定義 Schema(編寫 .xsd 檔案)
    2. 定義 JavaBean
    3. 編寫 NamespaceHandler 和 BeanDefinitionParser 完成 Schema 解析
    4. 編寫 spring.handlers 和 spring.schemas 檔案串聯解析部件
    5. 在 XML 檔案中應用配置
Dubbo 配置相關的程式碼在 dubbo-config 模組。

2.1 定義 Schema

Schema 的定義體現在 .xsd 檔案上,檔案位於 dubbo-config-spring 子模組下:

至於 XSD 的資料型別、如何定義,並不是本文的重點,請參考 W3school《Schema 教程》。

2.2 定義 JavaBean

dubbo-config-api 子模組中定義了 Dubbo 所有標籤對應的 JavaBean,JavaBean 裡面的屬性一一對應標籤的各配置項。

2.3 解析 Schema

Dubbo 服務框架的 Schema 的解析通過 DubboNamespaceHandler 和 DubboBeanDefinitionParser 實現。

其中,DubboNamespaceHandler 擴充套件了 Spring 的 NamespaceHandlerSupport,通過重寫它的 init() 方法給各個標籤註冊對應的解析器:

public class DubboNamespaceHandler extends NamespaceHandlerSupport {
    static {
        Version.checkDuplicate(DubboNamespaceHandler.class);
    }
    public void init() {
        registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
        registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
        registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
        registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
        registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
        registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
        registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
        registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
        registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
        registerBeanDefinitionParser("annotation", new DubboBeanDefinitionParser(AnnotationBean.class, true));
    }
}

DubboBeanDefinitionParser 實現了 Spring 的 BeanDefinitionParser,通過重寫 parse() 方法實現將標籤解析為對應的 JavaBean:

public class DubboBeanDefinitionParser implements BeanDefinitionParser {
    public BeanDefinition parse(Element element, ParserContext parserContext) {
    return parse(element, parserContext, beanClass, required);
    }

    @SuppressWarnings("unchecked")
    private static BeanDefinition parse(Element element,ParserContext parserContext,Class<?> beanClass,boolean required) {
        RootBeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setBeanClass(beanClass);
        beanDefinition.setLazyInit(false);
        //......省略
        if (ProtocolConfig.class.equals(beanClass)) {
            for (String name : parserContext.getRegistry().getBeanDefinitionNames()) {
                BeanDefinition definition = parserContext.getRegistry().getBeanDefinition(name);
                PropertyValue property = definition.getPropertyValues().getPropertyValue("protocol");
                if (property != null) {
                    Object value = property.getValue();
                    if (value instanceof ProtocolConfig && id.equals(((ProtocolConfig) value).getName())) {
                        definition.getPropertyValues().addPropertyValue("protocol", new RuntimeBeanReference(id));
                    }
                }
            }
        } else if (ServiceBean.class.equals(beanClass)) {
            String className = element.getAttribute("class");
            if(className != null && className.length() > 0) {
                RootBeanDefinition classDefinition = new RootBeanDefinition();
                classDefinition.setBeanClass(ReflectUtils.forName(className));
                classDefinition.setLazyInit(false);
                parseProperties(element.getChildNodes(), classDefinition);
                beanDefinition.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, id + "Impl"));
            }
        } else if (ProviderConfig.class.equals(beanClass)) {
            parseNested(element, parserContext, ServiceBean.class, true, "service", "provider", id, beanDefinition);
        } else if (ConsumerConfig.class.equals(beanClass)) {
            parseNested(element, parserContext, ReferenceBean.class, false, "reference", "consumer", id, beanDefinition);
        }
        //......省略
        return beanDefinition;
    }
}

2.4 串聯部件

上面我們已經知道解析的實現類了,那麼 Spring 又如何知道該用 DubboNamespaceHandler 來解析 Dubbo 標籤呢?這通過編寫 spring.handlers 檔案實現。

spring.handlers 內容如下:

http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler

然後,Spring 通過 spring.schemas 檔案得知 Dubbo 標籤的 Schema 是 dubbo.xsd,並以此校驗應用 XML 配置檔案的格式。

spring.schemas 檔案內容如下:

http\://code.alibabatech.com/schema/dubbo/dubbo.xsd=META-INF/dubbo.xsd

檔案位置如下:

2.5 應用配置

通過以上步驟,Dubbo 服務框架就完成了標籤解析的功能,使用者在應用程式中按照 dubbo.xsd 的格式配置 XML 即可。

Over.

相關推薦

Dubbo原理原始碼解析標籤解析

github新增倉庫 "dubbo-read"(點此檢視),集合所有《Dubbo原理和原始碼解析》系列文章,後續將繼續補充該系列,同時將針對Dubbo所做的功能擴充套件也進行分享。不定期更新,歡迎Follow。 一、Dubbo 配置方式 Dubbo 支援多種配置方式: XML 配置:基於

Dubbo原理原始碼解析服務暴露

github新增倉庫 "dubbo-read"(點此檢視),集合所有《Dubbo原理和原始碼解析》系列文章,後續將繼續補充該系列,同時將針對Dubbo所做的功能擴充套件也進行分享。不定期更新,歡迎Follow。 一、框架設計 在官方《Dubbo 使用者指南》架構部分,給出了服務呼叫的整體架構和

Dubbo原理原始碼解析“微核心+外掛”機制

private void loadFile(Map<String, Class<?>> extensionClasses, String dir) { //...... BufferedReader reader = new BufferedReader(new

Dubbo原理原始碼解析服務引用

github新增倉庫 "dubbo-read"(點此檢視),集合所有《Dubbo原理和原始碼解析》系列文章,後續將繼續補充該系列,同時將針對Dubbo所做的功能擴充套件也進行分享。不定期更新,歡迎Follow。 一、框架設計 在官方《Dubbo 開發指南》框架設計部分,給出了引用服務時序圖:

【NLP】Attention原理原始碼解析

對attention一直停留在淺層的理解,看了幾篇介紹思想及原理的文章,也沒實踐過,今天立個Flag,一天深入原理和原始碼!如果你也是處於attention model level one的狀態,那不妨好好看一下啦。 內容: 核心思想 原理解析(圖解+公式) 模型分類 優缺點 TF原始碼解析

Spring原始碼解析標籤解析下篇

正文 上篇文章我們介紹了Spring預設標籤的解析,本文我們來分析一下Spring自定義標籤的解析。上篇文章我們瞭解到Spring的預設標籤目前有4個(import、alias、bean、beans),也就是說除了這4個標籤以外的標籤都是自定義標籤(當然這裡所說的標籤不包括

Java執行緒池架構(一)原理原始碼解析

在前面介紹JUC的文章中,提到了關於執行緒池Execotors的建立介紹,在文章:《java之JUC系列-外部Tools》中第一部分有詳細的說明,請參閱; 文章中其實說明了外部的使用方式,但是沒有說內部是如何實現的,為了加深對實現的理解,在使用中可以放心,我們這裡將做原始碼解析以及反饋到原理上

演算法---hash演算法原理(java中HashMap底層實現原理原始碼解析)

散列表(Hash table,也叫雜湊表),是依據關鍵碼值(Key value)而直接進行訪問的資料結構。也就是說,它通過把關鍵碼值對映到表中一個位置來訪問記錄,以加快查詢的速度。這個對映函式叫做雜湊函式,存放記錄的陣列叫做散列表。  比如我們要儲存八十八個資料,我們為他申請了100個

jdk1.7的Java執行緒池架構原理原始碼解析(ThreadPoolExecutor)

我們現在來看看ThreadPoolExecutor的原始碼是怎麼樣的,也許你剛開始看他的原始碼會很痛苦,因為你不知道作者為什麼是這樣設計的,所以本文就我看到的思想會給你做一個介紹,此時也許你通過知道了一些作者的思想,你也許就知道應該該如何去操作了。 這裡來看下構造方法中對那

Java執行緒池架構原理原始碼解析(ThreadPoolExecutor)

在前面介紹JUC的文章中,提到了關於執行緒池Execotors的建立介紹,在文章:《java之JUC系列-外部Tools》中第一部分有詳細的說明,請參閱;文章中其實說明了外部的使用方式,但是沒有說內部是如何實現的,為了加深對實現的理解,在使用中可以放心,我們這裡將做原始碼解析

Springsecurity標籤解析

    注意:Springsecurity版本是4.3.x.RELEASE     在Springsecurity原始碼的config模組的resources/META-INF下有spring.handlers和spring.schemas,spring.

spice-gtk-0.35原始碼解析spicy解析

  spice-gtk介紹: spice-gtk是基於紅帽的spice遠端連線協議的一套客戶端核心原始碼,上層有一套virt-viewer也是客戶端原始碼,只不過spice-gtk屬於底層直接對話協議的專案,而virt-viewer是基於spice-gtk的更加偏向於介面的專案

Java多執行緒AQS(AbstractQueuedSynchronizer )實現原理原始碼分析(三)

章節概覽、 1、回顧 上一章節,我們分析了ReentrantLock的原始碼: 2、AQS 佇列同步器概述 本章節我們深入分析下AQS(AbstractQueuedSynchronizer)佇列同步器原始碼,AQS是用來構建鎖或者其他同步元件的基礎框架。

Java多執行緒Condition實現原理原始碼分析(四)

章節概覽、 1、概述 上面的幾個章節我們基於lock(),unlock()方法為入口,深入分析了獨佔鎖的獲取和釋放。這個章節我們在此基礎上,進一步分析AQS是如何實現await,signal功能。其功能上和synchronize的wait,notify一樣。

sqlite3原始碼解析sql解析(一)

一:sql準備過程在前面的分析中我們知道,sqlite3_open()為我們打開了資料庫並準備了所要的記憶體空間,鎖,vfs等。接下來就分析sql是如何被解析器一步一步解析的。上圖是準備sql語句的過程分析圖。  1.1:sqlite3_prepare_v2函式:該函數是準備

關於qemu的二三事(5)————qemu原始碼分析引數解析

目前,這個qemu的版本號是: [[email protected] x86_64-softmmu]# ./qemu-system-x86_64 --version QEMU emulator version 2.9.50 (v2.9.0-941-g0748

Java多執行緒ThreadPoolExecutor實現原理原始碼分析(五)

章節概覽、 1、概述 執行緒池的顧名思義,就是執行緒的一個集合。需要用到執行緒,從集合裡面取出即可。這樣設計主要的作用是優化執行緒的建立和銷燬而造成的資源浪費的情況。Java中的執行緒池的實現主要是JUC下面的ThreadPoolExecutor類完成的。下面

HTML基礎入門標籤解析

<form action="" method="get"> 使用者名稱:<input type="text"><br> 密碼:<input type="password"><br> 多選框:<br> <input type=

Java多執行緒ReentrantLock實現原理原始碼分析(二)

章節概覽、 1、ReentrantLock概述 ReentrantLock字面含義是可重入的互斥鎖,實現了和synchronize關鍵字一樣的獨佔鎖功能。但是ReentrantLock使用的是自旋鎖,通過CAS硬體原語指令實現的輕量級的鎖,不會引起上下文切換

spring原始碼深度解析---預設標籤解析(下)

spring原始碼深度解析—預設標籤解析(下) 在spring原始碼深度解析—預設標籤解析(上)中我們已經完成了從xml配置檔案到BeanDefinition的轉換,轉換後的例項是GenericBeanDefinition的例項。而GenericBeanDef