前言:Spring从2.0开始引入了一个新的机制用于扩展xml模式,我们就可以编写自定义的xml bean解析器然后集成到Spring IoC容器中(Spring不识别aop,mvc,这些标签都是通过本章要学习的内容,扩展标签

<mvc:interceptors></mvc:interceptors>
<aop:config></aop:config>


xml扩展大概有以下几个步骤:

  • 编写自定义类
  • 编写xml schema来描述自定义元素
  • 编写NamespaceHandler实现类
  • 编写BeanDefinitionParser实现类
  • 把以上组建注册到Spring

xml的schema约束:

先来说说xml文档的schema约束,它定义了xml文档的结构,内容和语法,包括元素和属性、关系的结构以及数据类型等等。有以下几点需要遵循:

1) 、所有的标签和属性都需要Schema来定义。(schema本身由w3c来定义)。

2)、所有的schema文件都需要以个ID,这里我们称之为 namespace,其值时一个url,通常是这个xml的xsd文件的地址。

3)、namespace值由 targetNamespace属性来指定

4)、引入一个schema约束,使用属性xmlns,属性值即为对应schema文件的命名空间 nameSpace。

5)、如果引入的schema非w3c组织定义的,必须指定schema文件的位置,schema文件的位置由 schemaLocation来指定。

6)、引入多个schema文件需要使用 别名。别名形式如下: xmlns:alias。

对于上述配置文件的详细解读:

1)、 声明默认的名称空间(xmlns="http://www.springframework.org/schema/beans")

2)、 声明XML Schema实例名称空间(http://www.w3.org/2001/XMLSchema-instance),并将xsi前缀与该名称空间绑定, 这样模式处理器就可以识别xsi:schemaLocation属性。XML Schema实例名称空间的前缀通常使用xsi

3)、 使 用xsi:schemaLocation属性指定名称空间(http://www.springframework.org/schema/beans) 和模式位置(http://www.springframework.org/schema/beans/spring-beans.xsd)相关。 XML Schema推荐标准中指出,xsi:schemaLocation属性可以在实例中的任何元素上使用,而不一定是根元素,不 过,xsi:schemaLocation属性必须出现在它要验证的任何元素和属性之前。

4)、使用别名引入多个schema文件。如上述 xmlns:mvc 、xmlns:tx 、xmlns:context等等。

编写自定义类

public class Miku {

   private String name;
   private int age;
   private char sex;
}

编写自定义schema,文件名为:miku.xsd,路径为:classpath:META-INF/miku.xsd

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

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

<xsd:element name="miku">
   <xsd:complexType>
      <xsd:complexContent>
         <xsd:extension base="beans:identifiedType">
            <xsd:attribute name="name" type="xsd:string" use="required"/>
            <xsd:attribute name="age" type="xsd:int"/>
            <xsd:attribute name="sex" type="xsd:char"/>
         </xsd:extension>
      </xsd:complexContent>
   </xsd:complexType>
</xsd:element>
</xsd:schema>



然后我们就可以像这样定义miku:
<miku :miku id="mymiku" name="hatsunemiku" age="16" sex="女"/>

编写NamespaceHandler

NamespaceHandler用于解析我们自定义名字空间下的所有元素,目前我们要解析上面的miku:miku元素。NamespaceHandler里面只有3个方法:

  • init()会在NamespaceHandler初始化的时候被调用。
  • BeanDefinition parse(Element, ParserContext) - 当Spring遇到一个顶层元素的时候被调用。
  • BeanDefinitionHolder decorate(Node, BeanDefinitionHolder, ParserContext) - 当Spring遇到一个属性或嵌套元素的时候调用.

Spring提供了默认实现类NamespaceHandlerSupport,我们只需在init的时候注册每个元素的解析器即可。

public class MikuNamespaceHandler extends NamespaceHandlerSupport {

   @Override
   public void init() {
      //遇到miku元素的时候交给MikuBeanDefinitionParser来解析
      registerBeanDefinitionParser("miku", new MikuBeanDefinitionParser());
   }
}

编写BeanDefinitionParser

当遇到miku元素时,Spring会交给MikuBeanDefinitionParser来解析。MikuBeanDefinitionParser取出相应的属性然后设置到bean中。

public class MikuBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {

   @Override
   protected Class<?> getBeanClass(Element element) {
      //miku元素对应Miku对象类型
      return Miku.class;
   }

   @Override
   protected void doParse(Element element, BeanDefinitionBuilder builder) {

      String name = element.getAttribute("name");
      String age = element.getAttribute("age");
      String sex = element.getAttribute("sex");

      //把对应的属性设置到bean中
      if(StringUtils.hasText(name))
         builder.addPropertyValue("name", name);

      if(StringUtils.hasText(age))
         builder.addPropertyValue("age", age);

      if(StringUtils.hasText(sex))
         builder.addPropertyValue("sex", sex);

   }
}

注册handler和schema(将组件串联起来)

为了让Spring在解析xml的时候能够感知到我们的自定义元素,我们需要把 namespaceHandler 和xsd文件放到2个指定的配置文件中,这2个文件都位于 META-INF 目录中。
META-INF/spring.handlers
spring.handlers 文件包含了xml schema uri和handler类的映射关系,比如:

http\://www.mycompany.com/schema/my=spring.xml.ext.schema.MikuNamespaceHandler

这表示遇到http\://www.mycompany.com/schema/my命名空间的时候会交给MikuNamespaceHandler来处理。

注意上面的冒号转义。 key部分必须和xsd文件中的targetNamespace值保持一致。

META-INF/spring.schemas
这样bean装载就完成了,写个测试开心的试一下吧~
转载请标明出处,本帖原创地址:http://blog.csdn.net/hatsune_miku_/article/details/77018869

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐