“This is the second day of my participation in the First Challenge 2022.

In addition to Spring’s default Namespace in the Spring XML configuration file, today we will look at how to customize a Namespace

1. Spring custom XML Namespace principle

Throughout the Spring container to start the process again, but at the time of loading the Bean definition, an XML configuration file is called AbstractXmlApplicationContext# loadBeanDefinitions method to load Bean definitions in the XML. Then XmlBeanDefinitionReader parses the XML from the set default location or the specified location into a Document into memory. BeanDefinitionDocumentReader responsible for each Element in the XML Document.

During the process, the mapping between the Namespace and the XSD file configured in the meta-INF/Spring. schemas is read and verified

In the process of parsing, the Namespace is determined to be the Spring default Namespace or the user-defined Namespace

  • Spring defaults to Element handling

    The default Element: import, alias, beans, beans, these are provided by default DefaultBeanDefinitionDocumentReader parsing

  • Custom Element handling

    Handlers by getting the handler class configured for a Namespace in the meta-INF/Spring. handlers file. The Namespace handler class implements NamespaceHandler or NamespaceHandlerSupport.

The Element is then parsed by calling the NamespaceHandler#parse method of the NamespaceHandler concrete instance.

2. Spring custom XML Namespace practice

Define an Element that has the same functionality as Spring’s default bean. This Element can be called mxsmBean.

2.1 XSD definitions

The XSD file defines what properties the mxsmBean needs to have.


      
<xsd:schema xmlns="https://github.com/mxsm/schema/mxsm"  (1)
            xmlns:xsd="http://www.w3.org/2001/XMLSchema"  
            targetNamespace="https://github.com/mxsm/schema/mxsm">  (2)

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

    <xsd:element name="mxsmBean">
        <xsd:complexType>
            <xsd:attribute name="name" type="xsd:string" use="required"/>
            <xsd:attribute name="class" type="xsd:string" use="required"/>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>
Copy the code

(1) and (2) add their own Namescape, where XSD is stored as follows:

2.2 Writing the Implementation of NamespaceHandler interface

This interface is mainly used to handle our corresponding Element. For example, in github.com/mxsm/schema… Now I’m just defining the Application Element so I only need to parse this one.

NamespaceHandlerSupport is an abstract method that implements part of the NamespaceHandler interface. Normally we implement the NamespaceHandlerSupport class

public class MxsmSchemaHandler extends NamespaceHandlerSupport {
    @Override
    public void init(a) {
        registerBeanDefinitionParser("mxsmBean".new MxsmBeanDefinitionParser());
        // Call multiple elements if there are multiple elements}}public class MxsmBeanDefinitionParser implements BeanDefinitionParser {

    @Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        String aClass = element.getAttribute("class");
        System.out.println(aClass);
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(aClass);
        AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        parserContext.getRegistry().registerBeanDefinition(element.getAttribute("name"), beanDefinition);
        returnbeanDefinition; }}Copy the code

Each corresponding tag corresponds to a parser class that implements the BeanDefinitionParser interface.

2.3 Configuring meta-INF /spring.schemas and meta-INF /spring.handlers file configuration

Spring. schemas Function: Configure the storage location of the XSD file of a user-defined Namespace

https\://github.com/mxsm/schema/mxsm/mxsm.xsd=com/github/mxsm/xml/xsd/mxsm.xsd
Copy the code

Handlers Function: Configure a NamespaceHandler for a user-defined Namespace

https\://github.com/mxsm/schema/mxsm=com.github.mxsm.handler.MxsmSchemaHandler
Copy the code

The location of storage in the project is shown as follows:

2.4 Introducing custom Elements in the Spring Application.xml file

Create the XML file for the Spring application.


      
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mxsm="https://github.com/mxsm/schema/mxsm"  (1)
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd https://github.com/mxsm/schema/mxsm (2) https://github.com/mxsm/schema/mxsm/mxsm.xsd (3) http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

        <mxsm:mxsmBean class="com.github.mxsm.bean.MxsmBeanTest" name="test"/>

</beans>
Copy the code

(1), (2), (3) these three need to be added when used. At this point, the customization steps are complete. The next step is to verify that we can inject this class into the Spring container. Here we write a test code to verify:

public class App {
    public static void main( String[] args ) {
        ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        //System.out.println(context.getBean("aaaa",String.class));
        MxsmBeanTest test = context.getBean("test", MxsmBeanTest.class); System.out.println(test); MxsmBeanTest bean = context.getBean(MxsmBeanTest.class); System.out.println(bean); System.out.println(test==bean); }}Copy the code

Then run to see the result:

It can be seen from the running result that the corresponding instance of MxsmBeanTest can be obtained, and it is still a singleton. So the definition that we registered in the Spring container when we created the default gets the class instance as a singleton by default.

Full code address: github.com/mxsm/spring…

3. Summary

  • Before you can customize an extension, first you need to know what the Element you are extending is for, and then parse it according to its purpose. For example, the mxsmBean above is intended to implement a simplified version of Spring’s default Bean functionality.
  • Namespace XSD file writing, the writing of the need to understand the XSD (tutorial reference: www.w3school.com.cn/schema/sche.)
  • NamespaceHandler and BeanDefinitionParser interfaces need to be implemented at the interface level, which were used previously.
  • Add configurations in the meta-INF /spring.schemas and meta-INF/spring.Handlers files, and Spring loads the configurations in these files for parsing by default.
  • Import the corresponding custom Namespace into the Spring XML configuration file.

Here’s how to customize a namespace, how to do it, and how Spring interprets it. For more details, visit the Spring website (docs. Spring. IO /spring-fram… Util (spring-util.xsd). You can learn from these. In this way, you can better understand and understand the process of customization.