Originating from Dubbo, talk about Spring XML Schema Extension Mechanism

Time:2019-9-29

background

In Dubbo, you can use XML to configure relevant information, or you can use it to import or export services. When the configuration is completed and the project is started, Spring reads the configuration file and generates injection-related beans. How does Dubbo implement custom XML read by Spring load?

Spring XML Schema extension mechanism. Starting with Spring 2.0, Spring has provided an XML Schema-based format extension mechanism for defining and configuring beans.

Spring XML Schema Extension Mechanism

Implementing Spring XML Schema extensions is actually very simple and requires only the following four steps.

  1. Create an XML Schema file, which is called an XSD file because it is suffixed with the name xsd.
  2. Write to implement one or moreBeanDefinitionParser
  3. To writeNamespaceHandlerImplementation class.
  4. registerNamespaceHandlerAnd XSD files.

Following the above steps, Spring finally parses the following configuration in its entirety.

<?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:demo="http://www.test.com/demo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd

        http://www.test.com/demo http://www.test.com/demo/demo.xsd">

    <demo:application name="test" id="test"/>
</beans>

Create XSD files

XSD file, mainly used to define the XML format, used to verify the validity of XML. In IDE, import XSD file and edit XML file to get relevant prompts.

Next we generate an XSD file.

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.test.com/demo"
            xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:beans="http://www.springframework.org/schema/beans"
            targetNamespace="http://www.test.com/demo"
            elementFormDefault="qualified"
            attributeFormDefault="unqualified">

    <xsd:import namespace="http://www.springframework.org/schema/beans"/>

    <xsd:element name="application">
        <xsd:complexType>
            <xsd:complexContent>
                <xsd:extension base="beans:identifiedType">
                    <xsd:attribute name="name" type="xsd:string" use="required"/>
                </xsd:extension>
            </xsd:complexContent>
        </xsd:complexType>
    </xsd:element>

</xsd:schema>

The XSD file abovehttp://www.test.com/demoTo customize the namespace address, you will use it below.

Implementing Bean Definition Parser

Realize hereBeanDefinitionParserThe real parsing of XML is done here.

Because the above example is relatively simple, we can directly inherit the abstract classes provided by Spring.AbstractSingleBeanDefinitionParserThen we can implement the relevant methods.

public class DemoBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {

    /**

     * Return the type that most needs to be injected into Spring Bean
     * @param element
     * @return
     */
    @Override
    protected Class<?> getBeanClass(Element element) {
        return DemoApplication.class;
    }

    /***
     * This method completes the real parsing action
     * @param element
     * @param builder
     */
    @Override
    protected void doParse(Element element, BeanDefinitionBuilder builder) {
        String name=element.getAttribute("name");
        builder.addPropertyValue("name",name);
    }
}

Of course, it can also be implemented directly.BeanDefinitionParserIt’s more flexible, but it’s more complicated than the one above.

public class BeanApplicationDefinitionParser implements BeanDefinitionParser {

    @Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {

        String name=element.getAttribute("name");
        // Bean definition, and finally production beans based on this
        RootBeanDefinition rootBeanDefinition=new RootBeanDefinition();
        rootBeanDefinition.setBeanClass(DemoApplication.class);
        rootBeanDefinition.setLazyInit(false);
        // Add parsed attributes
        rootBeanDefinition.getPropertyValues().add("name",name);
        // Register the generated Bean Definition, and missing this step will result in an error in the final generation of the Bean
        parserContext.getRegistry().registerBeanDefinition("application",rootBeanDefinition);
        return rootBeanDefinition;
    }
}

Implementing Namespace Handler

This step implements Namespace Handler, which developers customize as long as they inheritNamespaceHandlerSupportAbstract class, implementationinitMethod. Register the above step in this methodBeanDefinitionParser

public class DemoNameSpaceHandler extends NamespaceHandlerSupport {

    @Override

    public void init() {

        // elementName is the namespace
        registerBeanDefinitionParser("application",new BeanApplicationDefinitionParser());
    }
}

Register XSD and Namespace Handler

In this step, we need to generate two configuration files in META-INF, respectively.spring.handlersspring.schemas

spring.schemasSpecify the XSD file path.

http\://www.test.com/demo/demo.xsd=com/spring/learning/xml/schemas/autoring/leanrn/demo.xsd

spring.handlersAppointNamespaceHandlerThe full class name contains both the previous package name.

Notice here thatTransliteration is required

test run

First we produce Spring XML configuration files.

<?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:demo="http://www.test.com/demo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd

        http://www.test.com/demo http://www.test.com/demo/demo.xsd">

    <demo:application name="test" id="test"/>
</beans>

Note here that you need to use the definitions in the XSD filehttp://www.test.com/demo

Then we use SpringBoot to import the XML file and run it.

@SpringBootApplication
@ImportResource(locations = {"classpath:applicationContext.xml"})
public class XmlSchemaApplication {


    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(XmlSchemaApplication.class, args);
        DemoApplication demoApplication=applicationContext.getBean(DemoApplication.class);
        System.out.println("application name is "+demoApplication.getName());
    }
}

The output results are as follows:

Originating from Dubbo, talk about Spring XML Schema Extension Mechanism
application name is test

Research on Spring XML Extension Mechanism Source Code

Here we mainly study how custom XML extension files are loaded by Spring.

Spring will pass during startupBeanDefinitionDocumentReaderRead all the configurations in the beans tag, and this process will passBeanDefinitionParserDelegate#parseCustomElementParse custom elements.

Originating from Dubbo, talk about Spring XML Schema Extension Mechanism

The above parsing process can be customizedNamespaceHandlerThen callparse Method analysis.

Then let’s look at it.NamespaceHandlerResolver#resolveMethod to see how to get customizationNamespaceHandler

Originating from Dubbo, talk about Spring XML Schema Extension Mechanism

In this method, mainly fromhandlerMappingsGetting in CacheNamespaceHandler。 The cache originates fromgetHandlerMappingsMethod, which will load our custom abovespring.handlersPapers.

Originating from Dubbo, talk about Spring XML Schema Extension Mechanism

Read Spring LoadingNamespaceHandlerProcedure, let’s look at the most importantBeanDefinitionHow to generate.

As mentioned above, Spring will be usedNamespaceHandler.parseResolution, because we inheritedNamespaceHandlerSupportSee the implementation.

Originating from Dubbo, talk about Spring XML Schema Extension Mechanism

Originating from Dubbo, talk about Spring XML Schema Extension Mechanism

Getting BeanDefinition registers it in the container and then passes throughBeanDefinition Generate Beans. This generation process does not belong to the content of this chapter, so no longer outlined, interested students can search by themselves.

Dubbo XML Schema Extension Implementation

Finally, let’s look at how the Dubbo XML Schema extension is implemented.

Originating from Dubbo, talk about Spring XML Schema Extension Mechanism

Originating from Dubbo, talk about Spring XML Schema Extension Mechanism

You can see that the Dubbo XML Schema extension corresponds to the four standard Spring steps.

summary

Finally, a picture is used to summarize the whole text.

Originating from Dubbo, talk about Spring XML Schema Extension Mechanism

Help document

xsd-custom-registration
XML Schema Extension Mechanism in Spring

Originating from Dubbo, talk about Spring XML Schema Extension Mechanism