乐趣区

Dubbo之Schema自定义扩展

Dubbo 之 Schema 自定义扩展

Dubbo基于 Spring 提供的 NamespaceHandlerBeanDefinitionParser来扩展了自己XML Schemas,一切的功能也都是基于这一点来进行的。

基于 Spring 的自定义 Schema 扩展

1.Maven 依赖

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>5.1.6.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>5.1.6.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aop</artifactId>
  <version>5.1.6.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-beans</artifactId>
  <version>5.1.6.RELEASE</version>
</dependency>

2. 创建实体类

package com.lg.spring;

public class People {

    private String name;

    private int age;

    public String getName() {return name;}

    public void setName(String name) {this.name = name;}

    public int getAge() {return age;}

    public void setAge(int age) {this.age = age;}
}

3. 创建 Schema 文件

META-INF 目录下创建名为 people.xsd 的文件

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.people.com/schema/people"
            xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:beans="http://www.springframework.org/schema/beans"
            targetNamespace="http://www.people.com/schema/people"
            elementFormDefault="qualified"
            attributeFormDefault="unqualified">
    <xsd:import namespace="http://www.springframework.org/schema/beans"/>
    <xsd:element name="student">
        <xsd:complexType>
            <xsd:complexContent>
                <xsd:extension base="beans:identifiedType">

                    <xsd:attribute name="name" type="xsd:string">
                        <xsd:annotation>
                            <xsd:documentation> 姓名 </xsd:documentation>
                        </xsd:annotation>
                    </xsd:attribute>

                    <xsd:attribute name="age" type="xsd:string">
                        <xsd:annotation>
                            <xsd:documentation> 年龄 </xsd:documentation>
                        </xsd:annotation>
                    </xsd:attribute>

                </xsd:extension>
            </xsd:complexContent>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>

4. 创建相应的NamespaceHandler

package com.lg.spring;

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

public class PeopleNamespaceHandler extends NamespaceHandlerSupport {

    @Override
    public void init() {registerBeanDefinitionParser("person", new PeopleBeanDefinitionParser());
    }
}

5. 创建解析 Schema 文件的BeanDefinitionParser

package com.lg.spring;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;

public class PeopleBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {protected Class getBeanClass(Element element) {return People.class;}

    protected void doParse(Element element, BeanDefinitionBuilder bean) {String name = element.getAttribute("name");
        bean.addPropertyValue("name", name);

        String age = element.getAttribute("age");
        if (StringUtils.hasText(age)) {bean.addPropertyValue("age", Integer.valueOf(age));
        }
    }
}

6.spring.handlerspring.schema

META-INF目录下创建 spring.handler 如下:

http\://www.people.com/schema/people=com.lg.spring.PeopleNamespaceHandler

META-INF目录下创建 spring.schema 如下:

http\://www.people.com/schema/people.xsd=META-INF/people.xsd

7. 测试

META-INF 下创建applicationContext.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:people="http://www.people.com/schema/people"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans.xsd 
           http://www.people.com/schema/people 
           http://www.people.com/schema/people.xsd">

    <people:person id="person1" name="zhangsan" age="18"/>

    <bean id="person2" class="com.lg.spring.People">
        <property name="name" value="lisi"/>
        <property name="age" value="23"/>
    </bean>

</beans>

测试类:

package com.lg.spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class PeopleSchemaTest {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("/META-INF/applicationContext.xml");
        People person1 = (People) ctx.getBean("person1");
        People person2 = (People) ctx.getBean("person2");

        System.out.println("name:" + person1.getName() + "age :" + person1.getAge());
        System.out.println("name:" + person2.getName() + "age :" + person2.getAge());
    }
}

8. 结果

name: zhangsan age :18
name: lisi age :23

Dubbo 扩展的 Schema

1.Schema 文件

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:beans="http://www.springframework.org/schema/beans"
            xmlns:tool="http://www.springframework.org/schema/tool"
            xmlns="http://dubbo.apache.org/schema/dubbo"
            targetNamespace="http://dubbo.apache.org/schema/dubbo">

    <xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
    <xsd:import namespace="http://www.springframework.org/schema/beans" schemaLocation="http://www.springframework.org/schema/beans/spring-beans.xsd"/>
    <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:element name="protocol" type="protocolType">
        <xsd:annotation>
            <xsd:documentation><![CDATA[ Service provider config]]></xsd:documentation>
            <xsd:appinfo>
                <tool:annotation>
                    <tool:exports type="org.apache.dubbo.config.ProtocolConfig"/>
                </tool:annotation>
            </xsd:appinfo>
        </xsd:annotation>
    </xsd:element>

    <xsd:element name="service" type="serviceType">
        <xsd:annotation>
            <xsd:documentation><![CDATA[ Export service config]]></xsd:documentation>
            <xsd:appinfo>
                <tool:annotation>
                    <tool:exports type="org.apache.dubbo.config.ServiceConfig"/>
                </tool:annotation>
            </xsd:appinfo>
        </xsd:annotation>
    </xsd:element>

    <xsd:element name="reference" type="referenceType">
        <xsd:annotation>
            <xsd:documentation><![CDATA[ Reference service config]]></xsd:documentation>
            <xsd:appinfo>
                <tool:annotation>
                    <tool:exports type="org.apache.dubbo.config.ReferenceConfig"/>
                </tool:annotation>
            </xsd:appinfo>
        </xsd:annotation>
    </xsd:element>
  
    ...
  
</xsd:schema>

内容过长这里只粘处 servicereferenceprotocol三者

2.spring.handlerspring.schema 文件

http\://dubbo.apache.org/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
http\://code.alibabatech.com/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
http\://dubbo.apache.org/schema/dubbo/dubbo.xsd=META-INF/dubbo.xsd
http\://code.alibabatech.com/schema/dubbo/dubbo.xsd=META-INF/compat/dubbo.xsd

有两组是为了兼容 Dubbo 早期的版本。

3.DubboBeanDefinitionParser

package org.apache.dubbo.config.spring.schema;

...

import static org.apache.dubbo.common.constants.CommonConstants.HIDE_KEY_PREFIX;

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

4.DubboNamespaceHandler

package org.apache.dubbo.config.spring.schema;

import org.apache.dubbo.common.Version;

import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.MetadataReportConfig;
import org.apache.dubbo.config.ModuleConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.MonitorConfig;
import org.apache.dubbo.config.MetricsConfig;
import org.apache.dubbo.config.ProviderConfig;
import org.apache.dubbo.config.ConsumerConfig;
import org.apache.dubbo.config.ProtocolConfig;
import org.apache.dubbo.config.spring.ConfigCenterBean;
import org.apache.dubbo.config.spring.ReferenceBean;
import org.apache.dubbo.config.spring.ServiceBean;

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

public class DubboNamespaceHandler extends NamespaceHandlerSupport {

    static {Version.checkDuplicate(DubboNamespaceHandler.class);
    }

    @Override
    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("config-center", new DubboBeanDefinitionParser(ConfigCenterBean.class, true));
        registerBeanDefinitionParser("metadata-report", new DubboBeanDefinitionParser(MetadataReportConfig.class, true));
        registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
        registerBeanDefinitionParser("metrics", new DubboBeanDefinitionParser(MetricsConfig.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 AnnotationBeanDefinitionParser());
    }
}

可以看出 Dubbo 所有的组件都是由 DubboBeanDefinitionParser 来解析的,最后解析对应的 ServiceBean 等对象。

退出移动版