首先声明
Spring 2.0已经把aop、transaction/tx、jndi和Web MVC等等配置放入单独的namespace中(从spring.jar!/META-INF/spring.handlers中就能找到)。
老式的bean定义虽然可以适合绝大部分的配置工作,但是在一些特殊领域难免显得冗长拖沓,这些领域往往有自己的领域定义,继续沿用老式的bean定义除了会把人搞晕以外倒也没有其他恶行,这种情景之下,使用自己的namespace然后通过自定义的NamespaceHandler去注册bean可以使得编写XML配置的时候更加符合特定领域的语义要求,增强XML文件的可读性。
代码均摘抄自spring-reference.pdf
分为四步:
第一: Authoringan XML schema to describe your custom element(s).
为你自定义的元素编写一个xml schema文档
- <!-- myns.xsd (inside package org/springframework/samples/xml) -->
- <?xml version="1.0" encoding="UTF-8"?>
- <xsd:schemaxmlnsxsd:schemaxmlns="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:importnamespacexsd:importnamespace="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>
照这种形式使用
- <myns:dateformatidmyns:dateformatid="dateFormat"
- pattern="yyyy-MM-dd HH:mm"
- lenient="true"/>
得到的与下述代码一样
- <bean id="dateFormat" class="java.text.SimpleDateFormat">
- <constructor-argvalueconstructor-argvalue="yyyy-HH-dd HH:mm"/>
- <property name="lenient" value="true"/>
- </bean>
备注:我schema编写能力不行,得学习
第二步:Coding aNamespaceHandler(实现一个NamespaceHandler)
NamespaceHandler这个接口是很简单的,只有三个方法
- • init()- allows for initialization of the NamespaceHandlerand will be called by Spring before
- the handler is used
- • BeanDefinition parse(Element, ParserContext)- called when Spring encounters a top-level element (not nested inside a bean definition or a different namespace). This method can
- register bean definitions itself and/or return a bean definition.
- • BeanDefinitionHolder decorate(Node, BeanDefinitionHolder, ParserContext)
- called when Spring encounters an attribute or nested element of a different namespace.
但是spring给我们提供了一个实现了大量公共的逻辑抽象类,我们只需要继承它就行了,不需要重复写很多繁琐的代码,这个类就是NamespaceHandlerSupport
- package org.springframework.samples.xml;
- import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
- public class MyNamespaceHandler extends NamespaceHandlerSupport {
- public void init() {
- registerBeanDefinitionParser("dateformat", new SimpleDateFormatBeanDefinitionParser());
- }
- }
这个类中,你可以注册许多BeanDefinitionParsers,每一个BeanDefinitionParsers用于解析一个自定义element。
第三步:Coding a BeanDefinitionParser(编写一个 BeanDefinitionParser类)
- package org.springframework.samples.xml;
- 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 {
- protected Class getBeanClass(Element element) {
- return SimpleDateFormat.class; #
- }
- 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.addConstructorArg(pattern);
- // this however is an optional property
- String lenient = element.getAttribute("lenient");
- if (StringUtils.hasText(lenient)) {
- bean.addPropertyValue("lenient", Boolean.valueOf(lenient));
- }
- }
- }
同样的,我们也可以继承 AbstractSingleBeanDefinitionParser 这个类 个人觉得,当你只需要注册一个BeanDefinitionParser的时候,你可以继承 AbstractSingleBeanDefinitionParser 这个抽象类,但是如果你的 NamespaceHandler需要多个 BeanDefinitionParser。你就不应该继承这个类。应该继承另外一个抽象类(已验证)
第四步:Registering the handler and the schema(把咱们写的hanlder和schema让spring知道)
编码已经完成了,接下来,我们需要分开将我们自定义的namespaceHandler和schema注册到spring.handlers.properties和spring.schemas.properties文件中,然后将文件放到自己的项目的META-INF文件夹中,注意,名字一定不能改。
spring.handlers.properties中配置格式
(注意,properties文件中分号是特殊字符,所以需要转义)
http\://www.mycompany.com/schema/myns=org.springframework.samples.xml.MyNamespaceHandler
spring.schemas.properties中的配置格式
(此处分号也是需要转义的)
http\://www.mycompany.com/schema/myns/myns.xsd=org/springframework/samples/xml/myns.xsd
第五步:现在你就可以使用了
- <?xml version="1.0" encoding="UTF-8"?>
- <beansxmlnsbeansxmlns="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-3.0.xsd
- http://www.mycompany.com/schema/myns http://www.mycompany.com/schema/myns/myns.xsd">
- <!-- as a top-level bean -->
- <myns:dateformat id="defaultDateFormat" pattern="yyyy-MM-dd HH:mm" lenient="true"/>
- <bean id="jobDetailTemplate" abstract="true">
- <property name="dateFormat">
- <!-- as an inner bean -->
- <myns:dateformat pattern="HH:mm MM-dd-yyyy"/>
- </property>
- </bean>
- </beans>
比较简单,算是一个介绍把。感谢