如何在spring自定义命名空间和处理器(上)

spring中的自定义名称空间是用更友好的配置替换复杂bean定义的一种方式

文章目录

      • 第一步:Schema定义
      • 第二步:NameSpaceHandler(命名空间处理器)
      • 第三步 spring.handlers
      • 第四步 spring.schemas
      • 第五步 BeanDefinitionParser
      • 应用例子
      • 个人分析和理解

  • Spring 本身提供了几个现成的名称空间。例如, 有关,的翻译,请参考此帖子

  • 让我们以示例场景为例,并逐步执行创建自定义名称空间以及处理程序的步骤。

  • 命名空间的例子

  • 考虑如下类:

  • // dao类
    public class MyDAO {
     
     private List<String> fields;
     
     public List<String> getFields() {
      return fields;
     }
     
     public void setFields(List<String> fields) {
      this.fields = fields;
     }
     
    }
    
    // 服务类
    public class MyService {
     
     private String serviceName;
     private MyDAO defaultDao;
     private Map<String, MyDAO> daoRegistry;
     
     public String getServiceName() {
      return serviceName;
     }
     
     public void setServiceName(String serviceName) {
      this.serviceName = serviceName;
     }
     
     public MyDAO getDefaultDao() {
      return defaultDao;
     }
     
     public void setDefaultDao(MyDAO defaultDao) {
      this.defaultDao = defaultDao;
     }
     
     public Map<String, MyDAO> getDaoRegistry() {
      return daoRegistry;
     }
     
     public void setDaoRegistry(Map<String, MyDAO> daoRegistry) {
      this.daoRegistry = daoRegistry;
     }
     
    }
    
  • 假设我们使用以下一组bean实例化这些类

    • <bean id="myservice-123" class="com.codelooru.dos.MyService">
              <property name="defaultDao" ref="mydao-123" />
              <property name="serviceName" value="myservice" />
              <property name="daoRegistry">
                  <map>
                      <entry key="dao1" value-ref="mydao-123" />
                  map>
              property>
          bean>
      
          <bean id="mydao-123" class="com.codelooru.dos.MyDAO">
              <property name="fields">
                  <list>
                      <value>field1value>
                      <value>field2value>
                      <value>field3value>
                  list>
              property>
          bean>
      
  • 现在,我想用非常简单的内容替换这些Bean定义,例如:

    • <createservice daoid="mydao-123" fields="field1,field2,field3" serviceid="myservice-123">
      createservice>
      
      

第一步:Schema定义

  • 为我们的自定义XML元素定义Schema

  • createservice元素的schema如下,自定义命名空间为http://www.codelooru.com/custns

  • <xs:schema elementformdefault="qualified" targetnamespace="http://www.codelooru.com/custns" xmlns:tns="http://www.codelooru.com/custns" xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <xs:element name="createservice">
        <xs:complextype>
          <xs:attribute name="serviceId" type="xs:string" use="required">
          <xs:attribute name="daoId" type="xs:string" use="required">
          <xs:attribute name="fields" type="xs:string" use="required">
        xs:attribute>xs:attribute>xs:attribute>xs:complextype>
      xs:element>
    xs:schema>
    

第二步:NameSpaceHandler(命名空间处理器)

  • 为上述定义的命名空间创建命名空间处理程序,定制命名空间处理程序应实现org.springframework.beans.factory.xml.NamespaceHandler接口。Spring提供了一个便利类org.springframework.beans.factory.xml.NamespaceHandlerSupport, 该类提供了一种通过单个处理程序注册多个命名空间解析器的方法。

  • public class CustomNamespaceHandler extends NamespaceHandlerSupport {
     
     public void init() {
      registerBeanDefinitionParser("createservice", new CreateServiceNamespaceBeanDefinitionParser());
     }
     
    }
    
  • init方法应为所需元素注册所有bean定义解析器。

  • 对于createservice元素,我们将定义一个新的BeanDefinitionparser, 这将在第5步中详细介绍

第三步 spring.handlers

  • 在META-INF下创建文件"spring.handlers", 并为名称空间注册处理程序。

  • http\://www.codelooru.com/custns=com.codelooru.custns.CustomNamespaceHandler
    
    
  • 当Spring Bean XML 中遇到名称空间时,Spring会调用此处理程序

第四步 spring.schemas

  • 在META-INF下创建文件"spring.schemas", 并注册命名空间的schema定义文件。

  • http\://www.codelooru.com/custns.xsd=schema.xsd
    
    
  • Spring会根据提供的schema定义来验证bean XML中的元素

第五步 BeanDefinitionParser

  • 创建一个自定义的BeanDefinitionParser, 它将解析createservice元素并生成bean 定义。 解析器应实现org.springframework.beans.factory.xml.BeanDefinitionParser.

  • public class CreateServiceNamespaceBeanDefinitionParser implements BeanDefinitionParser {
     
     public BeanDefinition parse(Element element, ParserContext parserContext) {
      //parsing 
       
      BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MyDAO.class);
      builder.addPropertyValue("fields", Arrays.asList(element.getAttribute("fields").split(",")));
       
      String daoId = element.getAttribute("daoId");
      parserContext.getRegistry().registerBeanDefinition(daoId, builder.getBeanDefinition());
     
      ManagedMap<Object, Object> map = new ManagedMap<Object, Object>();
      map.put("dao1", new RuntimeBeanReference(daoId));
       
      builder = BeanDefinitionBuilder.genericBeanDefinition(MyService.class);
      builder.addPropertyValue("serviceName", "myservice");
      builder.addPropertyReference("defaultDao", daoId);
      builder.addPropertyValue("daoRegistry", map);
       
      parserContext.getRegistry().registerBeanDefinition(element.getAttribute("serviceId"), builder.getBeanDefinition());
       
      return null;
     }
     
    }
    
    • 实现parse方法,该方法为createservice元素和ParserContext提供org.w3c.dom.Element对象。
    • ParserContext为您提供访问BeanDefinitionRegistry的权限,我们将使用它来注册我们的bean
    • BeanDefinitionBuilder.genericBeanDefinition(Someclass), 为提供的类创建一个新的bean定义
    • 您可以通过在构建器上使用addPropertyValue来设置属性的值。第一个参数将是属性名称,第二个参数将是实际值。值可以是任何类型。
    • 如果要为引用bean设置属性,请使用RuntimeBeanReference.
    • 如果您的值是具有一个或多个引用的列表,请使用org.springframework.beans.factory.support.ManagedList定义列表。
    • 如果您的值是具有一个或多个引用的map,请使用org.springframework.beans.factory.support.ManagedMap定义Map。
    • 您可以使用addPropertyReference将属性设置为引用另一个bean。第一个参数将是属性名称,第二个参数将是被引用bean的名称。
    • 一旦定义了bean,就可以通过parserContext.getRegistry(). registerBeanDefinition方法进行注册。它以bean的id作为第一个参数,以BeanDefinition作为第二个参数。

应用例子

GitHub project.

个人分析和理解

你可能感兴趣的:(springframework,namespace,命名空间,自定义,spring.handlers,xml标签)