Dubbo源码-Dubbo是如何随心所欲自定义XML标签的

Posted JackieZheng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dubbo源码-Dubbo是如何随心所欲自定义XML标签的相关的知识,希望对你有一定的参考价值。

当前浏览器不支持播放音乐或语音,请在微信或其他浏览器中播放 Dubbo源码-Dubbo是如何随心所欲自定义XML标签的

叨叨

今天考虑了很久要不要写这篇文章。

距离《Dubbo源码》系列的开篇到现在已经快两个月时间了。当时是想着工作上的RPC框架使用存在一些让人头疼的问题,就来看看Dubbo给出了一套什么样的解决方案。

结果,写完第一篇没几天,工作上因为要赶一个项目的进度,关小黑屋了,前段时间刚放出来-_-!

琢磨着,做事不能半途而废。今天就又打开了Dubbo项目,pull下代码,在十多个子模块之间来回滚动,感觉都不是好惹的,一时不知道从哪下手了。再一想,Dubbo源码系列不能就这么唐突的出一篇就结束了啊。

行,思来想去,还是接着从上篇提到的dubbo-demo模块继续往下说……

正文

下面是dubbo-demo-provider模块下的dubbo-demo-provider.xml配置文件内容

<?xml version="1.0" encoding="UTF-8"?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
  -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <!-- provider's application name, used for tracing dependency relationship -->
    <dubbo:application name="demo-provider"/>

    <!-- use zookeeper registry center to export service -->
    <dubbo:registry address="zookeeper://127.0.0.1:2181"/>

    <!-- use dubbo protocol to export service on port 20880 -->
    <dubbo:protocol name="dubbo" port="20880"/>

    <!-- service implementation, as same as regular local bean -->
    <bean id="demoService" class="com.alibaba.dubbo.demo.provider.DemoServiceImpl"/>

    <!-- declare the service interface to be exported -->
    <dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService"/>

</beans>

注意:这里的dubbo:registry在上篇已经说明,有过改动,这里使用的是zookeeper的配置

dubbo-demo-provider与常见的xml文件有何不同

1、除了<bean id="demoService" ... 其他的标签我们日常都没有使用过

2、 标签中除了常见的“http://www.springframework.org/schema/beans/spring-beans-4.3.xsd”还多了“http://dubbo.apache.org/schema/dubbo/dubbo.xsd”

我们平常使用的xml都是在Spring框架下,所以可以看到熟悉的 等。那有没有想过,为什么定义一个 标签就是生命一个bean,就能够在Spring上下文注册一个类的实例呢?其实,这些工作Spring在幕后都帮我们做好了,这个我在之前的《Spring读书笔记》系列有着重写过。

稍稍扫一眼Dubbo的代码,就会发现,Dubbo也是基于Spring开发的,使用了Spring的很多特性,但是鉴于自己的业务框架需求,需要做相应的拓展和定制化,实现一套自己的自定义XML标签。那么这些标签又是如何生效和被使用的呢

基于Spring的Schema提供自定义配置支持

在dubbo-demo-provider.xml中见到的那些标签也是基于Spring的Schema实现的一套自定义标签。

这一套流程主要包括以下几个步骤:

  • 编写配置类和属性

  • 编写XSD文件

  • 编写spring.handlers和spring.schemas

  • 编写DubboNamespaceHandler和DubboBeanDefinitionParser,主要负责标签解析

编写配置类和属性

针对dubbo-demo-provider中的<dubbo:application name="demo-provider"/>来说,该标签对应的配置类在dubbo-config-api模块下的ApplicationConfig。

package com.alibaba.dubbo.config;

import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.compiler.support.AdaptiveCompiler;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import com.alibaba.dubbo.config.support.Parameter;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * ApplicationConfig
 *
 * @export
 */
public class ApplicationConfig extends AbstractConfig {

    private static final long serialVersionUID = 5508512956753757169L;

    // application name
    private String name;

    // module version
    private String version;

    // application owner
    private String owner;

    // application's organization (BU)
    private String organization;

    // architecture layer
    private String architecture;

    // environment, e.g. dev, test or production
    private String environment;

    // Java compiler
    private String compiler;

    // logger
    private String logger;

    // registry centers
    private List<RegistryConfig> registries;

    // monitor center
    private MonitorConfig monitor;

    // is default or not
    private Boolean isDefault;

    // directory for saving thread dump
    private String dumpDirectory;

    private Boolean qosEnable;

    private Integer qosPort;

    private Boolean qosAcceptForeignIp;

    // customized parameters
    private Map<String, String> parameters;

    public ApplicationConfig() {
    }

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

    @Parameter(key = Constants.APPLICATION_KEY, required = true)
    public String getName() {
        return name;
    }

    public void setName(String name) {
        checkName("name", name);
        this.name = name;
        if (id == null || id.length() == 0) {
            id = name;
        }
    }

    @Parameter(key = "application.version")
    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    public String getOwner() {
        return owner;
    }

    public void setOwner(String owner) {
        checkMultiName("owner", owner);
        this.owner = owner;
    }

    public String getOrganization() {
        return organization;
    }

    public void setOrganization(String organization) {
        checkName("organization", organization);
        this.organization = organization;
    }

    public String getArchitecture() {
        return architecture;
    }

    public void setArchitecture(String architecture) {
        checkName("architecture", architecture);
        this.architecture = architecture;
    }

    public String getEnvironment() {
        return environment;
    }

    public void setEnvironment(String environment) {
        checkName("environment", environment);
        if (environment != null) {
            if (!("develop".equals(environment) || "test".equals(environment) || "product".equals(environment))) {
                throw new IllegalStateException("Unsupported environment: " + environment + ", only support develop/test/product, default is product.");
            }
        }
        this.environment = environment;
    }

    public RegistryConfig getRegistry() {
        return registries == null || registries.isEmpty() ? null : registries.get(0);
    }

    public void setRegistry(RegistryConfig registry) {
        List<RegistryConfig> registries = new ArrayList<RegistryConfig>(1);
        registries.add(registry);
        this.registries = registries;
    }

    public List<RegistryConfig> getRegistries() {
        return registries;
    }

    @SuppressWarnings({"unchecked"})
    public void setRegistries(List<? extends RegistryConfig> registries) {
        this.registries = (List<RegistryConfig>) registries;
    }

    public MonitorConfig getMonitor() {
        return monitor;
    }

    public void setMonitor(MonitorConfig monitor) {
        this.monitor = monitor;
    }

    public void setMonitor(String monitor) {
        this.monitor = new MonitorConfig(monitor);
    }

    public String getCompiler() {
        return compiler;
    }

    public void setCompiler(String compiler) {
        this.compiler = compiler;
        AdaptiveCompiler.setDefaultCompiler(compiler);
    }

    public String getLogger() {
        return logger;
    }

    public void setLogger(String logger) {
        this.logger = logger;
        LoggerFactory.setLoggerAdapter(logger);
    }

    public Boolean isDefault() {
        return isDefault;
    }

    public void setDefault(Boolean isDefault) {
        this.isDefault = isDefault;
    }

    @Parameter(key = Constants.DUMP_DIRECTORY)
    public String getDumpDirectory() {
        return dumpDirectory;
    }

    public void setDumpDirectory(String dumpDirectory) {
        this.dumpDirectory = dumpDirectory;
    }

    @Parameter(key = Constants.QOS_ENABLE)
    public Boolean getQosEnable() {
        return qosEnable;
    }

    public void setQosEnable(Boolean qosEnable) {
        this.qosEnable = qosEnable;
    }

    @Parameter(key = Constants.QOS_PORT)
    public Integer getQosPort() {
        return qosPort;
    }

    public void setQosPort(Integer qosPort) {
        this.qosPort = qosPort;
    }

    @Parameter(key = Constants.ACCEPT_FOREIGN_IP)
    public Boolean getQosAcceptForeignIp() {
        return qosAcceptForeignIp;
    }

    public void setQosAcceptForeignIp(Boolean qosAcceptForeignIp) {
        this.qosAcceptForeignIp = qosAcceptForeignIp;
    }

    public Map<String, String> getParameters() {
        return parameters;
    }

    public void setParameters(Map<String, String> parameters) {
        checkParameterName(parameters);
        this.parameters = parameters;
    }
}

在ApplicationConfig同级目录下,还包括其他出现在dubbo-demo-provider.xml中出现自定义标签类,如RegistryConfig、ProtocolConfig