分布式服务Dubbo从入门到"精通"之Schema实现

前言

尽管使用了Dubbo许久,但其实对于其了解还是九牛一毛,上个月通读了Netty实战(粗略的了解),突然有了解读Dubbo源码的欲望,时不待我,那就赶紧开始吧。

熟悉Dubbo的朋友,可能都知道其采用全Spring配置方式,透明化接入应用,对应用没有任何API侵入,只需用Spring加载Dubbo的配置即可,Dubbo基于Spring的Schema扩展进行加载。

当然,如果你不想使用Spring配置,而希望通过API的方式进行调用,Dubbo也是支持的,但是官方是不推荐的(原因你猜)。

今天,就跟大家聊一聊Dubbo是如何基于Schema实现的。

准备

1329440-740c239f41566b16.png

具体实现,需要使用到一下几个配置或者是类: spring.handlers:解析所使用的类 spring.schemas:自定义标签的路径 DubboNamespaceHandler.java:处理器 DubboBeanDefinitionParser.java:解析器 xxxxConfig.java:JavaBean建模

实现

这里我们以dubbo:application做案例介绍

实体类ApplicationConfig.java

位于com.alibaba.dubbo.config包下,截取部分代码:

public class ApplicationConfig extends AbstractConfig {
    private static final long serialVersionUID = 5508512956753757169L;
    private String name;
    private String version;
    private String owner;
    private String organization;
    private String architecture;
    private String environment;
    private String compiler;
    private String logger;
    private List<RegistryConfig> registries;
    private MonitorConfig monitor;
    private Boolean isDefault;

    public ApplicationConfig() {
    }

    public ApplicationConfig(String name) {
        setName(name);
    }

编写dubbo.xsd文件

位于META-INF下,截取部分代码:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns="http://code.alibabatech.com/schema/dubbo"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:tool="http://www.springframework.org/schema/tool"
    targetNamespace="http://code.alibabatech.com/schema/dubbo">
    
    <xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
    <xsd:import namespace="http://www.springframework.org/schema/beans"/>
    <xsd:import namespace="http://www.springframework.org/schema/tool"/>

    <xsd:annotation>
        <xsd:documentation><![CDATA[ Namespace support for the dubbo services provided by dubbo framework. ]]></xsd:documentation>
    </xsd:annotation>
    
    <xsd:complexType name="applicationType">
        <xsd:attribute name="id" type="xsd:ID">
            <xsd:annotation>
                <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="name" type="xsd:string" use="required">
            <xsd:annotation>
                <xsd:documentation><![CDATA[ The application name. ]]></xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="version" type="xsd:string">
            <xsd:annotation>
                <xsd:documentation><![CDATA[ The application version. ]]></xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="owner" type="xsd:string">
            <xsd:annotation>
                <xsd:documentation><![CDATA[ The application owner name (email prefix). ]]></xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="organization" type="xsd:string">
            <xsd:annotation>
                <xsd:documentation><![CDATA[ The organization name. ]]></xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="architecture" type="xsd:string">
            <xsd:annotation>
                <xsd:documentation><![CDATA[ The architecture. ]]></xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="environment" type="xsd:string">
            <xsd:annotation>
                <xsd:documentation><![CDATA[ The application environment, eg: dev/test/run ]]></xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="compiler" type="xsd:string">
            <xsd:annotation>
                <xsd:documentation><![CDATA[ The java code compiler. ]]></xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="logger" type="xsd:string">
            <xsd:annotation>
                <xsd:documentation><![CDATA[ The application logger. ]]></xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="registry" type="xsd:string" use="optional">
            <xsd:annotation>
                <xsd:documentation><![CDATA[ The application registry. ]]></xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="monitor" type="xsd:string" use="optional">
            <xsd:annotation>
                <xsd:documentation><![CDATA[ The application monitor. ]]></xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="default" type="xsd:string" use="optional">
            <xsd:annotation>
                <xsd:documentation><![CDATA[ Is default. ]]></xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
    </xsd:complexType>
    
    <xsd:element name="annotation" type="annotationType">
        <xsd:annotation> 
            <xsd:documentation><![CDATA[ The annotation config ]]></xsd:documentation> 
        </xsd:annotation>
    </xsd:element>
</xsd:schema>

关于xsd:schema的各个属性具体含义就不作过多陈述,大家可以参见

http://www.w3school.com.cn/schema/schema_elements_ref.asp

DubboBeanDefinitionParser和DubboNamespaceHandler实现解析

DubboNamespaceHandler会根据schema和节点名找到某个DubboBeanDefinitionParser,然后由DubboBeanDefinitionParser完成具体的解析工作。因此需要分别继承NamespaceHandlerSupport和实现BeanDefinitionParser类。

两个类都位于com.alibaba.dubbo.config.spring.schema包下,以下是DubboNamespaceHandler部分代码:

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.handlers和spring.schemas

编码完毕之后,还需要做一些配置工作。我们必须告诉Spring我们准备使用自定义的标签元素,告诉Spring如何解析元素,否则Spring没那么聪明。这里需要2个配置文件,spring.handlers和spring.schemas(位于META-INF下即可),用于告诉Spring自定义标签的文档结构以及解析它的类。两个文件内容分别如下:

spring.handlers:

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

spring.schemas:

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

spring-context-dubbo.xml

好了,最终呈现给大家的就是这个样子:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://code.alibabatech.com/schema/dubbo
        http://code.alibabatech.com/schema/dubbo/dubbo.xsd
        ">
    <!-- 提供方应用信息,用于计算依赖关系  部分代码-->
    <dubbo:application name="itstyle" />
</beans>

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏函数式编程语言及工具

ScalaPB(2): 在scala中用gRPC实现微服务

2553
来自专栏技术墨客

Spring核心——IOC处理器扩展 原

Spring一直标注自己是一个非侵入式框架。非侵入式设计的概念并不新鲜,目标就是降低使用者和框架代码的耦合,毕竟框架的开发者和使用者几乎肯定不是同一个团队。Sp...

642
来自专栏冰枫

Spring容器初始化完成的回调方法

我们可能经常会碰到一些奇奇怪怪的需求,比如在IOC容器初始化完成前实例化一些bean,bean的初始化回调等等等。今天来讲一下如何实现Spring IOC容器如...

74818
来自专栏DT乱“码”

Memcached使用实例

package com.memcached.util; import java.io.BufferedWriter; import java.io.FileW...

2206
来自专栏菩提树下的杨过

dubbo/dubbox 增加原生thrift及avro支持

(facebook) thrift / (hadoop) avro / (google) probuf(grpc)是近几年来比较抢眼的高效序列化/rpc框架,d...

4058
来自专栏wannshan(javaer,RPC)

dubbo请求处理线程模型实现分析

问题的由来: 如果事件处理的逻辑能迅速完成,并且不会发起新的 IO 请求,比如只是在内存中记个标识, 则直接在 IO 线程上处理更快,因为减少了线程池调度。 ...

1.3K10
来自专栏尾尾部落

[剑指offer] 从尾到头打印链表

一种方法是利用栈来实现; 另外一种方法是利用三个指针把链表反转,关键是 r 指针保存断开的节点。

931
来自专栏Ryan Miao

使用dropwizard(6)-国际化-easy-i18n

前言 Dropwizard官方文档并没有提供国际化的模块,所以只能自己加。Spring的MessageResource用的很顺手,所以copy过来。 Easy...

37712
来自专栏javathings

ApplicationListener 和@EventListener 注解实现事件监听

对于 Spring 容器的一些事件,可以监听并且触发相应的方法。通常的方法有 2 种,ApplicationListener 接口和@EventListener...

1.6K3
来自专栏冰枫

dubbo源码——服务提供者的服务暴露过程(一)

<dubbo:xxx/>标签是Spring的自定义标签,可以查看dubbo.jar包下的META-INF->spring.handlers

9959

扫码关注云+社区

领取腾讯云代金券