Spring custom namespace
Explanation
When Spring parses the tags in the xml file, it will distinguish whether the current tag is four basic tags (import, alias, bean and beans) or a custom tag. If it is a custom tag, it will parse the current according to the logic of the custom tag s Mark.
Starting from version 2.0, the Spring framework provides an extension mechanism for defining beans based on the Schema-style Spring XML format. The introduction of Schema-based XML is to simplify the traditional XML configuration form.
Through the definition of Schema, some configuration forms that originally need to be defined by the definition of several beans or a combination of complex beans are presented in another simple and readable configuration form.
Schema-based XML consists of three parts:
- namespace-has a very clear logical classification
- element-has very clear process semantics
- attributes-has very simple configuration options
E.g:
<mvc:annotation-driven />
The meaning of this configuration is to realize Annotation-driven configuration in the space of mvc.
among them,
mvc
Indicates the effective range of the configuration,annotation-driven
It expresses a dynamic process, the actual logical meaning is: the implementation of the entire SpringMVC is based on the Annotation mode, please register the relevant behavior mode for me.
customize
The following will explain how to write custom XML bean definition parsing and integrate this parsing into the Spring IOC container.
In the following content we will mention an important concept is the bean definition. In fact, there is an important concept in Spring is the bean. And the BeanDefinition object is the corresponding label after parsing the object.
You can create a new xml configuration extension using the following short answer steps:
- Authoring an XML schema to describe your custom element (s)
- Coding a custom NamespaceHandler implementation (this is a very simple step, don't worry)
- Coding one or more BeanDefinitionParse implementation (this is the most important)
- Registeringr register the above to Spring (this is also a short answer step)
Examples
We need to create an XML extension (custom xml element) that allows us to configure the SimpleDateFormat object (in the java.text package) in a simple way. Finally, we can define a simpleDateFormat type bean definition as follows:
<myns:dateformat id="dateFormat"
pattern="yyyy-MM-dd HH:mm"
lenient="true"/>
1. Create a configuration
Create a file in the resources of the project:
myns.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.mycompany.com/schema/myns"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:beans="http://www.springframework.org/schema/beans"
targetNamespace="http://www.mycompany.com/schema/myns"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xsd:import namespace="http://www.springframework.org/schema/beans"/>
<xsd:element name="dateformat">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="beans:identifiedType">
<xsd:attribute name="lenient" type="xsd:boolean"/>
<xsd:attribute name="pattern" type="xsd:string" use="required"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
</xsd:schema>
The above schema will be used to configure the SimpleDateFormat object.
Used directly in a xml application context file <myns:dateformat />
.
<myns:dateformat id="dateFormat"
pattern="yyyy-MM-dd HH:mm"
lenient="true"/>
Note: The XML fragment above is essentially the same as the XML fragment below.
<bean id="dateFormat" class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-HH-dd HH:mm"/>
<property name="lenient" value="true"/>
</bean>
2. Write a namespace processor
For the above schema, we need NamespaceHandler
to parse all of the specific namespace
configuration files encountered by Spring elements
. This NamespaceHandler
will care about the parsing myns:dateformat
elements.
The NamespaceHandler interface is relatively simple, and it includes three important methods.
init()
-NamespaceHandler will be instantiated before spring uses handlerBeanDefinition parse(Element, ParseContext)
-When Spring encounters the top-level element (that is, myms) defined above, it will be called.This method can register bean definitions and can return a bean definition.BeanDefinitionHolder decorate(Node, BeanDefinitionHolder, ParserContext)
-Spring will be called when it encounters an attribute or element embedded in the namespace.
MyNamespaceHandler.java
package com.jeiker.namespace;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
public class MyNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("dateformat", new SimpleDateFormatBeanDefinitionParser());
}
}
3. Parse custom xml elements
The responsibility of BeanDefinitionParser is to parse XML elements that define the schema at the top-level. During the parsing process, we must access the XML elements, so we can parse our custom XML content.
SimpleDateFormatBeanDefinitionParser.java
package com.jeiker.namespace;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
import java.text.SimpleDateFormat;
public class SimpleDateFormatBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected Class getBeanClass(Element element) {
return SimpleDateFormat.class;
}
@Override
protected void doParse(Element element, BeanDefinitionBuilder bean) {
// this will never be null since the schema explicitly requires that a value be supplied
String pattern = element.getAttribute("pattern");
bean.addConstructorArgValue(pattern);
// this however is an optional property
String lenient = element.getAttribute("lenient");
if (StringUtils.hasText(lenient)) {
bean.addPropertyValue("lenient", Boolean.valueOf(lenient));
}
}
}
note:
- We use AbstractSingleBeanDefinitionParser provided by Spring to handle some basic work of creating a single BeanDefinition.
- We rewrote the doParse method of the AbstractSingleBeanDefinitionParser parent class to implement our own logic for creating a single-type BeanDefinition.
4. Register the schema and handler in Spring
4.1 Registration schema
Create in resources
META-INF/spring.schemas
http\://www.mycompany.com/schema/myns/myns.xsd=xml/myns.xsd
4.2 Register handler
Create in resources
META-INF/spring.handlers
http\://www.mycompany.com/schema/myns=com.jeiker.namespace.MyNamespaceHandler
5. Test
5.1 Configure schema-beans.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:myns="http://www.mycompany.com/schema/myns"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.mycompany.com/schema/myns http://www.mycompany.com/schema/myns/myns.xsd">
<myns:dateformat id="dateFormat"
pattern="yyyy-MM-dd HH:mm"
lenient="true"/>
</beans>
5.2 Test category
package com.jeiker.namespace;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.text.SimpleDateFormat;
import java.util.Date;
public class SchemaBeanDefinitionTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("schema-beans.xml");
SimpleDateFormat dateFormat = context.getBean("dateFormat", SimpleDateFormat.class);
System.out.println("-------------------gain object--------------------");
System.out.println(dateFormat);
String dateStr = dateFormat.format(new Date());
System.out.println(dateStr);
}
}