spring和spring_探索Spring创作

spring和spring

在本文中,我将描述Spring的一个有用但未被充分利用的功能,即Spring bean定义文件中的自定义标签的定义。

Spring名称空间

我将从以Spring文档为例的简单示例开始。 在2.0版之前,只有一个XML模式可用。 因此,为了使一个常量可以作为bean使用,并将其注入其他bean,必须定义以下内容:

<beanid="java.sql.Connection.TRANSACTION_SERIALIZABLE"
  class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean"/>

Spring使它成为可能,但是意识到将常量公开为bean只是一个技巧。 但是,从Spring 2.0开始,该框架允许您使用util名称空间,从而使前面的示例变为:

<util:constantstatic-field="java.sql.Connection.TRANSACTION_SERIALIZABLE"/>

实际上,现在有许多名称空间可用:

字首 命名空间 描述

bean

http://www.springframework.org/schema/bean

Original bean schema

util

http://www.springframework.org/schema/util

Utilities: constants, property paths and collections

jee

http://www.springframework.org/schema/jee

JNDI lookup

lang

http://www.springframework.org/schema/lang

Use of other languages

tx

http://www.springframework.org/schema/tx

Transactions

aop

http://www.springframework.org/schema/aop

AOP

context

http://www.springframework.org/schema/context

ApplicationContext manipulation

如第一个示例所示,每个选项都旨在减少冗长程度并提高可读性。

创作

许多人仍然不知道该功能是可扩展的,Spring API为您提供了编写自己的功能的途径。 实际上,许多框架提供者都应该利用这一点并提供自己的名称空间,以便更轻松地将其产品与Spring集成。 有些已经做到了:想到了带有许多名称空间的 CXF ,但应该有其他我不认识的名称空间

创建您自己的名称空间的过程分为4个步骤:关于XML验证的2个步骤,另外两个用于创建bean本身。 为了说明该过程,我将使用一个简单的示例:我将为EhCache (Hibernate的默认缓存引擎)创建一个架构。

基础bean工厂将是现有的EhCacheFactoryBean 。 因此,它不会像真正的功能那样有用,但是它将使我们专注于真正的编写管道,而不是EhCache实现细节。

创建模式

创建模式是关于描述XML语法,更重要的是限制。 我希望我的XML如下所示:

<ehcache:cacheid="myCache"eternal="true"cacheName="foo"
maxElementsInMemory="5"maxElementsOnDisk="2"overflowToDisk="false"
diskExpiryThreadIntervalSeconds="18"diskPersistent="true"timeToIdle="25"timeToLive="50"
memoryStoreEvictionPolicy="FIFO">
  <ehcache:managerref="someManagerRef"/>
</ehcache:echcache>

因为我不会假定要教任何人有关XML的知识,所以这里是模式。 只要注意名称空间声明即可:

<xsd:schemaxmlns:xsd="http://www.w3.org/2001/XMLSchema"
  targetNamespace="http://blog.frankel.ch/spring/ehcache"xmlns="http://blog.frankel.ch/spring/ehcache"
  elementFormDefault="qualified">
  <xsd:complexTypename="cacheType">
    <xsd:sequencemaxOccurs="1"minOccurs="0">
      <xsd:elementname="manager"type="managerType"/>
    </xsd:sequence>
    <xsd:attributename="id"type="xsd:string"/>
    <xsd:attributename="cacheName"type="xsd:string"/>
    <xsd:attributename="diskExpiryThreadIntervalSeconds"type="xsd:int"/>
    <xsd:attributename="diskPersistent"type="xsd:boolean"/>
    <xsd:attributename="eternal"type="xsd:boolean"/>
    <xsd:attributename="maxElementsInMemory"type="xsd:int"/>
    <xsd:attributename="maxElementsOnDisk"type="xsd:int"/>
    <xsd:attributename="overflowToDisk"type="xsd:boolean"/>
    <xsd:attributename="timeToLive"type="xsd:int"/>
    <xsd:attributename="timeToIdle"type="xsd:int"/>
    <xsd:attributename="memoryStoreEvictionPolicy"type="memoryStoreEvictionPolicyType"/>
  </xsd:complexType>
  <xsd:simpleTypename="memoryStoreEvictionPolicyType">
    <xsd:restrictionbase="xsd:string">
      <xsd:enumerationvalue="LRU"/>
      <xsd:enumerationvalue="LFU"/>
      <xsd:enumerationvalue="FIFO"/>
    </xsd:restriction>
  </xsd:simpleType>
  <xsd:complexTypename="managerType">
    <xsd:attributename="ref"type="xsd:string"/>
  </xsd:complexType>
  <xsd:elementname="cache"type="cacheType"/>
</xsd:schema>

对于像我一样喜欢图形显示的人:

Spring的EhCache XML模式

映射架构

模式创建只是第一部分。 现在,我们必须让Spring意识到这一点。 创建文件META-INF / spring.schemas并在下面的行中写就足够了:

http\://blog.frankel.ch/spring/schema/custom.xsd=ch/frankel/blog/spring/authoring/custom.xsd

请小心插入反斜杠,否则它将不起作用。 它将XML中的模式声明映射到将在jar中使用的真实文件!

在更进一步和好奇之前,请注意在spring-beans.jar(v3.0)中有一个这样的文件。 内容如下:

http\://www.springframework.org/schema/beans/spring-beans-2.0.xsd=org/springframework/beans/factory/xml/spring-beans-2.0.xsd
http\://www.springframework.org/schema/beans/spring-beans-2.5.xsd=org/springframework/beans/factory/xml/spring-beans-2.5.xsd
http\://www.springframework.org/schema/beans/spring-beans-3.0.xsd=org/springframework/beans/factory/xml/spring-beans-3.0.xsd
http\://www.springframework.org/schema/beans/spring-beans.xsd=org/springframework/beans/factory/xml/spring-beans-3.0.xsd
http\://www.springframework.org/schema/tool/spring-tool-2.0.xsd=org/springframework/beans/factory/xml/spring-tool-2.0.xsd
http\://www.springframework.org/schema/tool/spring-tool-2.5.xsd=org/springframework/beans/factory/xml/spring-tool-2.5.xsd
http\://www.springframework.org/schema/tool/spring-tool-3.0.xsd=org/springframework/beans/factory/xml/spring-tool-3.0.xsd
http\://www.springframework.org/schema/tool/spring-tool.xsd=org/springframework/beans/factory/xml/spring-tool-3.0.xsd
http\://www.springframework.org/schema/util/spring-util-2.0.xsd=org/springframework/beans/factory/xml/spring-util-2.0.xsd
http\://www.springframework.org/schema/util/spring-util-2.5.xsd=org/springframework/beans/factory/xml/spring-util-2.5.xsd
http\://www.springframework.org/schema/util/spring-util-3.0.xsd=org/springframework/beans/factory/xml/spring-util-3.0.xsd
http\://www.springframework.org/schema/util/spring-util.xsd=org/springframework/beans/factory/xml/spring-util-3.0.xsd

它带来一些注释:

  • 春天吃自己的狗粮(很高兴知道)
  • 我没有研究代码,但是我认为这就是为什么对Spring Bean文件的XML验证永远不会抱怨无法通过Internet找到架构(由于防火墙安全性问题,在生产环境中确实很痛苦)。 那是因为XSD是在罐子里看的
  • 如果您未指定要使用的Spring模式的版本(2.0、2.5、3.0等),则Spring将使用jar的每个主要/次要版本自动为您升级它。 如果您想要这种行为,很好,否则,您必须指定版本

创建解析器

前面的步骤仅用于验证XML,以使eternal属性采用布尔值。 我们仍然没有将名称空间连接到Spring工厂。 这是此步骤的目标。

首先要做的是创建一个实现org.springframework.beans.factory.xml.BeanDefinitionParser的类。 从其层次结构来看,似乎org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser是一个很好的入口点,因为:

  • XML不太复杂
  • 将只有一个bean定义

这是代码:

publicclassEhCacheBeanDefinitionParserextendsAbstractSimpleBeanDefinitionParser{

  privatestaticfinalList<String>PROP_TAG_NAMES;

  static{
  PROP_TAG_NAMES=newArrayList();
    PROP_TAG_NAMES.add("eternal");
    PROP_TAG_NAMES.add("cacheName");
    PROP_TAG_NAMES.add("maxElementsInMemory");
    PROP_TAG_NAMES.add("maxElementsOnDisk");
    PROP_TAG_NAMES.add("overflowToDisk");
    PROP_TAG_NAMES.add("diskExpiryThreadIntervalSeconds");
    PROP_TAG_NAMES.add("diskPersistent");
    PROP_TAG_NAMES.add("timeToLive");
    PROP_TAG_NAMES.add("timeToIdle");
  }

  @Override
  protectedClassgetBeanClass(Elementelement){
    returnEhCacheFactoryBean.class;
  }

  @Override
  protectedbooleanshouldGenerateIdAsFallback(){
    returntrue;
  }

  @Override
  protectedvoiddoParse(Elementelement,ParserContextparserContext,BeanDefinitionBuilderbuilder){
    for(Stringname:PROP_TAG_NAMES){
      Stringvalue=element.getAttribute(name);
      if(StringUtils.hasText(value)){
        builder.addPropertyValue(name,value);
      }
    }
    NodeListnodes=element.getElementsByTagNameNS("http://blog.frankel.ch/spring/ehcache","manager");
    if(nodes.getLength()>0){
      builder.addPropertyReference("cacheManager",
        nodes.item(0).getAttributes().getNamedItem("ref").getNodeValue());
    }
    Stringmsep=element.getAttribute("memoryStoreEvictionPolicy");
    if(StringUtils.hasText(msep)){
      MemoryStoreEvictionPolicypolicy=MemoryStoreEvictionPolicy.fromString(msep);
      builder.addPropertyValue("memoryStoreEvictionPolicy",policy);
    }
  }
}

这值得一些解释。 静态块填充哪些属性有效。 getBeanClass()方法返回将使用的类,直接用作Bean或用作工厂。 shouldGenerateIdAsFallback()方法用于告诉Spring,如果XML中没有提供ID,则应生成一个ID。 这样就可以创建伪匿名Bean(在Spring工厂中,没有一个Bean真正是匿名的)。

真正的魔力发生在doParse()方法中:它只是添加在构建器中找到的每个简单属性。 但是,有两个有趣的属性: cacheManagermemoryStoreEvictionPolicy

前者(如果存在)是对另一个bean的引用。 因此,不应将其作为参考值添加到构建器中。 当然,代码不会检查开发人员是否在ehcache内将缓存管理器声明为匿名Bean,但是模式验证已经解决了这一问题。

后者仅使用字符串值来获取真实对象,并将其作为属性添加到构建器。 同样,由于该值是在架构上枚举的,因此不会发生由语法错误引起的异常。

注册解析器

最后一步是在Spring中注册解析器。 首先,您只需要创建一个扩展org.springframework.beans.factory.xml.NamespaceHandlerSupport的类,并在其init()方法中以XML标记名称注册处理程序:

publicclassEhCacheNamespaceHandlerextendsNamespaceHandlerSupport{
  publicvoidinit(){
    registerBeanDefinitionParser("cache",newEhCacheBeanDefinitionParser());
  }
}

如果您有更多解析器,只需在每个标签名称下以相同的方法注册它们即可。

其次,只需将先前创建的名称空间映射到文件META-INF / spring.handlers中的新创建的处理程序:

http\://blog.frankel.ch/spring/ehcache=ch.frankel.blog.spring.authoring.ehcache.EhCacheNamespaceHandler

请注意,您将声明的架构文件映射到实际架构,但将名称空间映射到处理程序。

结论

现在,当面对过于冗长的bean配置时,您可以选择使用这种漂亮的4步技术来简化它。 当然,该技术更面向产品提供者,但是可以由项目使用,前提是编写名称空间所花的时间比常规bean定义要实时得多。

您可以在此处以Maven / Eclipse格式找到本文的资源。

翻译自: https://blog.frankel.ch/discover-spring-authoring/

spring和spring

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值