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

github新增倉庫 "dubbo-read"(點此查看),集合全部《Dubbo原理和源碼解析》系列文章,後續將繼續補充該系列,同時將針對Dubbo所作的功能擴展也進行分享。不按期更新,歡迎Follow。

 

1、Dubbo 配置方式

Dubbo 支持多種配置方式:git

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

對於 屬性配置 方式,能夠經過環境變量、-D 啓動參數來指定 dubbo.properties 文件,加載文件順序爲:github

    1. -D 啓動參數
    2. 環境變量
    3. classpath 根目錄

加載代碼以下:spring

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 配置的實現原理和源碼,其餘方式不予贅述。api

2、XML 配置

文章開頭已經提到,XML 配置方式是基於 Spring 的 Schema 和 XML 擴展機制實現的。經過該機制,咱們能夠編寫本身的 Schema,並根據自定義的 Schema 自定義標籤來配置 Bean。app

使用 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 子模塊下:ide

至於 XSD 的數據類型、如何定義,並非本文的重點,請參考 W3school《Schema 教程》。ui

2.2 定義 JavaBean

dubbo-config-api 子模塊中定義了 Dubbo 全部標籤對應的 JavaBean,JavaBean 裏面的屬性一一對應標籤的各配置項。編碼

2.3 解析 Schema

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

其中,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.

相關文章
相關標籤/搜索