Spring学习笔记(三)基于XML Schema的配置方式

前言:Spring2.0开始,Spring允许使用基于XML Schema的配置方式来简化Spring配置文件,这种方式更加简洁,可以对Spring配置文件进行“减肥”。
  Spring配置文件的基本配置的<beans>标签包含如下配置:

<?xml version="1.0" encoding="GBK"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://www.springframework.org/schema/beans"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
</beans>

  其中已经包含了一个最基本的Schema:spring-beans-4.0.xsd,也是默认的命名空间。如果对XML命名空间不了解的可以从参考:XML学习笔记

一、Spring中的Schema机制解析

  Spring在启动时是要检验XML文件的,如果我们打开上面的xmlns后面的链接,不难发现那是保存各个版本spring-beans-*.xsd的远程文档。如果断网,name就无法访问这些文件了,Spring已经将此情况考虑进去了,Spring默认从本地加载XSD文件。

  首先说明Spring创建Schema的基本过程:

  1. 设计配置属性和JavaBean。也就是设计好配置项,并通过JavaBean来建模。
  2. 编写XSD文件。(详细可参考:Schema 教程
  3. 编写NamespaceHandler和BeanDefinitionParser完成解析工作
  4. 编写spring.handlers和spring.schemas串联起所有部件
  5. 在Bean文件中应用。

  下面重点说明一下第四/五步,第四步是编写NamespaceHandler和BeanDefinitionParser完成解析工作,具体说来 NamespaceHandler会根据schema和节点名找到某个BeanDefinitionParser,然后由 BeanDefinitionParser完成具体的解析工作,开发好的handler与xsd还没法让应用感知到,这就需要将它们串联起来。第五步是编写spring.handlers和spring.schemas串联起所有部件,这两个文件的地址必须是META-INF/spring.handlers和META-INF/spring.schemas,spring会默认去 载入它们

<1> spring.handlers

  spring.handlers文件官网解释:The properties file called 'spring.handlers' contains a mapping of XML Schema URIs to namespace handler classes.

http\://www.mycompany.com/schema/myns=org.springframework.samples.xml.MyNamespaceHandler

  The ':' character is a valid delimiter in the Java properties format, and so the':' character in the URI needs to be escaped with a backslash.
  The first part (the key) of the key-value pair is the URI associated(关联) with your custom(自定义) namespace extension(拓展), and needs to match(匹配) exactly(精确地) the value of the'targetNamespace'attribute(属性) as specified in your custom XSD schema.

  也就是说spring.handlers文件保存的是XML Schema的URI与NamespaceHandler类的映射关系,这是一个property文件,因此是kye-value的形式,其中key是我们在XSD Schema中'targetNamespace'属性所指定的命名空间的名字,其中冒号需要转义,而其对应的值就是解析这个命名空间的NamespaceHandler。

<2> spring.schemas

  spring.schemas文件官网解释:The properties file called 'spring.schemas' contains a mapping of XML Schema locations(referred to along with the schema declaration in XML files that use the schema as partof the'xsi:schemaLocation' attribute) to classpath resources. This file is neededto prevent Spring from absolutely having to use a defaultEntityResolver that requiresInternet access to retrieve the schema file. If you specify the mapping in thisproperties file, Spring will search for the schema on the classpath (in this case'myns.xsd' in the'org.springframework.samples.xml' package):

http\://www.mycompany.com/schema/myns/myns.xsd=org/springframework/samples/xml/myns.xsd

  The upshot of this is that you are encouraged to deploy your XSD file(s) right alongsidetheNamespaceHandler andBeanDefinitionParser classes on the classpath.
  也就是说spring.handlers包含的是XML Schema文件本地存储的映射关系,其键值对中的值都可以在文件中找到。这个文件中保存的键都是可以在引用的XML文件中的xsi:schemaLocation属性中引用。

注意:在该文件中有一个没有指定版本的特殊键值对,这也就是说没有指定版本的时候,会指定这个属性所指定的对应版本,一般是当前版本的版本号。

1.1 Spring的XML校验

  使用xmlns指定命名空间,其中起别名是很常见的例如:

xmlns:p="http://www.springframework.org/schema/p

  这样在下面以p冒号开头的都是使用的是这个命名空间中,可以看出这个网址的最后面的符号与别名是相同的;不知你们有没有这个疑问,加入我前面的别名与网址最后的民称不一样例如上面的命名空间我写成如:xmlns:p_text="http://www.springframework.org/schema/p,经过测试能使用,前面只不过是一个引用的别名,但是不推荐这样,还是写成前后都一致的比较好,这样便于理解,参考资料也都是这样写的,别搞另类了。

  通常情况下,namespace对应的URI是一个存放XSD的地址,尽管规范没有这么要求。如果没有提供schemaLocation,那么Spring的XML解析器会从namespace的URI里加载XSD文件。我们可以把配置文件改成这个样子,也是可以正常工作的:

<beans xmlns="http://www.springframework.org/schema/beans/spring-beans.xsd"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">  

  schemaLocation属性提供了一个xml namespace到对应的XSD文件的一个映射,所以我们可以看到,在xsi:schemaLocation后面配置的字符串都是成对的,前面的是namespace的URI,后面是xsd文件的URI。比如:

    xsi:schemaLocation="http://www.springframework.org/schema/beans  
    http://www.springframework.org/schema/beans/spring-beans.xsd  
    http://www.springframework.org/schema/security  
    http://www.springframework.org/schema/security/spring-security.xsd"  

注:The 'xsi:schemaLocation' fragment is not actually required, but can be included to reference a local copy of a schema (which can be useful during development).

1.2 Spring的namespace的列表

参考地址:http://stackoverflow.com/questions/11174286/spring-xml-namespaces-how-do-i-find-what-are-the-implementing-classes-behind-t

Spring core

  • aop - AopNamespaceHandler
  • c - SimpleConstructorNamespaceHandler
  • cache - CacheNamespaceHandler
  • context - ContextNamespaceHandler
  • jdbc - JdbcNamespaceHandler
  • jee - JeeNamespaceHandler
  • jms - JmsNamespaceHandler
  • lang - LangNamespaceHandler
  • mvc - MvcNamespaceHandler
  • oxm - OxmNamespaceHandler
  • p - SimplePropertyNamespaceHandler
  • task - TaskNamespaceHandler
  • tx - TxNamespaceHandler
  • util - UtilNamespaceHandler

Spring Security

  • security - SecurityNamespaceHandler
  • oauth - OAuthSecurityNamespaceHandler

Spring integration

  • int - IntegrationNamespaceHandler
  • amqp - AmqpNamespaceHandler
  • event - EventNamespaceHandler
  • feed - FeedNamespaceHandler
  • file - FileNamespaceHandler
  • ftp - FtpNamespaceHandler
  • gemfire - GemfireIntegrationNamespaceHandler
  • groovy - GroovyNamespaceHandler
  • http - HttpNamespaceHandler
  • ip - IpNamespaceHandler
  • jdbc - JdbcNamespaceHandler
  • jms - JmsNamespaceHandler
  • jmx - JmxNamespaceHandler
  • mail - MailNamespaceHandler
  • redis - RedisNamespaceHandler
  • rmi - RmiNamespaceHandler
  • script - ScriptNamespaceHandler
  • security - IntegrationSecurityNamespaceHandler
  • sftp - SftpNamespaceHandler
  • stream - StreamNamespaceHandler
  • twitter - TwitterNamespaceHandler
  • ws - WsNamespaceHandler
  • xml - IntegrationXmlNamespaceHandler
  • xmpp - XmppNamespaceHandler

  可以查看对应的JavaDoc文档进行查看。

二、常用详细解析

<?xml version="1.0" encoding="GBK"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://www.springframework.org/schema/beans"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
</beans>

  这是最基本的根元素配置,我们不难发现其中默认的命名空间是xmlns="http://www.springframework.org/schema/beans",我们找到到spring-beans-*.jar包下的META-INF/spring.handlers文件,如下:

http\://www.springframework.org/schema/c=org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandler
http\://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler
http\://www.springframework.org/schema/util=org.springframework.beans.factory.xml.UtilNamespaceHandler

  可以看出,其中已经包含了三个命名空间,我们不要误解为:如果我们使用这三个命名空间,则无须指定其XSD文件的位置,直接使用xmlns属性指定别名即可使用。

  其中前两个确实是不用指定特定的,但是第三个util是需要指定对应的XSD文件的。

注:the p-namespace and c-namespace is not defined in an XSD file and exists only in the core of Spring。也就是说p和c命名空间并没有在XSD文件中定义,而是直接存在于Spring内核中。

注:Spring框架解压缩包的schema包含了所有Spring的XML Schema文件。官网参考文档可参考:VIII. Appendices -> 40. XML Schema-based configuration

2.1 使用p-namespace简化XML配置

官方使用文档可参考(spring-framework-4.2.5.RELEASE-dist):III. Core Technologies -> 6.4. Dependencies -> 6.4.2. Dependencies and configuration in detail -> XML shortcut with the p-namespace

  使用p-namespace前,需要导入XML Schema里的p-namespace,只需要在<beans.../>标签中添加xmlns:p="http://www.springframework.org/schema/p"即可,如下:

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
...
</beans>

  前面所提及的设值注入,如下:

<bean id="chinese" class="org.crazyit.app.service.impl.Chinese">  
    <!-- 驱动调用chinese的setAxe()方法,将容器中stoneAxe作为传入参数 -->  
    <property name="axe" ref="stoneAxe"/>  
</bean>  
<!-- 配置stoneAxe实例,其实现类是StoneAxe -->  
<bean id="stoneAxe" class="org.crazyit.app.service.impl.StoneAxe"/>  
<!-- 配置steelAxe实例,其实现类是SteelAxe -->  
<bean id="steelAxe" class="org.crazyit.app.service.impl.SteelAxe"/> 

  我们使用p-namespace的话可以达到同样的效果,如下:

<!-- 驱动调用chinese的setAxe()方法,将容器中stoneAxe作为传入参数 --> 
<bean id="chinese" class="org.crazyit.app.service.impl.Chinese"
	p:axe-ref="stoneAxe"/>  
<!-- 配置stoneAxe实例,其实现类是StoneAxe -->  
<bean id="stoneAxe" class="org.crazyit.app.service.impl.StoneAxe"/>  
<!-- 配置steelAxe实例,其实现类是SteelAxe -->  
<bean id="steelAxe" class="org.crazyit.app.service.impl.SteelAxe"/> 

  首先从行数,代码量上来说后者减少了很多,其次其更加清晰明了,减少了XML的层次,变子元素为属性,而且将原本属于子元素的两个属性只使用一个元素就可以表示。

  使用也非常简单:如果需要注入的参数不需要引用容器中另一个已存在的bean实例,则直接使用该需要注入的字段的名称,作为属性的key;否则,则需要在注入字段的名称后面加上“-ref”,然后作为属性的key。如上面示例中需要注入的字段名为axe,因为其引用了另外一个Bean,所以在axe后面添加上了“-ref”即可。

注意:使用p-namespace没有标准的XML格式灵活,如果某个Bean属性名以“-ref”结尾的,那么采用p-namespace定义时就会发生冲突,而采用标准的XML格式定义则不会出现这种问题。

2.2 使用c-namespace简化XML配置

官方使用文档可参考(spring-framework-4.2.5.RELEASE-dist):III. Core Technologies -> 6.4. Dependencies -> 6.4.2. Dependencies and configuration in detail -> XML shortcut with the c-namespace

  c-namespace与p-namespace这两个命名空间是直接存在于Spring内核中的,p-namespace主要是用于简化设值注入,而c-namespace则用于简化构造注入。

  使用方法与p-namespace类同,首先在<beans.../>中添加:xmlns:c="http://www.springframework.org/schema/c",示例如下:

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://www.springframework.org/schema/beans"
	xmlns:c="http://www.springframework.org/schema/c"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
	<!-- 配置chinese实例,其实现类是Chinese -->
	<bean id="chinese" class="org.crazyit.app.service.impl.Chinese"
		c:axe-ref="steelAxe" c:age="29"/>
	<!-- 配置chinese实例,其实现类是Chinese -->
	<bean id="chinese2" class="org.crazyit.app.service.impl.Chinese"
		c:_0-ref="steelAxe" c:_1="29"/>
	<!-- 配置stoneAxe实例,其实现类是StoneAxe -->
	<bean id="stoneAxe" class="org.crazyit.app.service.impl.StoneAxe"/>
	<!-- 配置steelAxe实例,其实现类是SteelAxe -->
	<bean id="steelAxe" class="org.crazyit.app.service.impl.SteelAxe"/>
</beans>

  上面配置方式是在c:后使用构造器参数名来指定构造器参数,Spring还支持一种通过索引来配置构造器参数的方式。上面的Bean也可改写为如下形式:

<bean id="chinese" class="org.crazyit.app.service.impl.Chinese"
		c:_0-ref="steelAxe" c:_1="29"/>

  代码中c:_0-ref指定使用容器中已有的steelAxe Bean作为第一个构造器参数,c:_1="29"则指定使用29作为第二个构造器参数。在这种方式下,c:_N代表第几个构造器参数。
注意: the c-namespace, newly introduced in Spring 3.1。c-namespace是Spring3.1才添加的。

2.3 util schema

  As the name implies, the util tags deal with common, utility configuration issues, such as configuring collections, referencing constants, and suchlike.

  顾名思义,util标签处理常见的、实用的配置问题,例如配置集合,引用常量等。

  To use the tags in the util schema, you need to have the following preamble at the top of your Spring XML configuration file; the text in the snippet below references the correct schema so that the tags in the util namespace are available to you.

<?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:util="http://www.springframework.org/schema/util" 
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <!-- bean definitions here -->

</beans>

  在util Schema下提供了如下几个元素:

  • constant:该元素用于获取指定类的静态Field的值。它是FieldRetrievingFactoryBean的简化配置
  • property-path:该元素用于获取指定对象的getter方法的返回值。它是PropertyPathFactory的简化配置
  • List:该元素用于定义一个List Bean,支持使用<value.../>、<ref.../>、<bean.../>等子元素来定义List集合元素。使用该标签支持如下三个属性:
    • id:该属性指定定义一个名为id的List Bean实例
    • list-class:该属性指定Spring使用哪个List实现类来创建Bean实例。默认使用ArrayList作为实现类
    • scope:指定该List Bean实例的作用域
  • Set:该元素用于定义一个Set Bean,支持使用<value.../>、<ref.../>、<bean.../>等子元素来定义Set集合元素。使用该标签支持如下三个属性:
    • id:该属性指定定义一个名为id的Set Bean实例
    • set-class:该属性指定Spring使用哪个Set 实现类来创建Bean实例。默认使用HashSet作为实现类
    • scope:指定该Set Bean实例的作用域
  • Map:该元素用于定义一个Map Bean,支持使用<entry.../>来定义Map的key-value对。使用该标签支持如下三个属性:
    • id:该属性指定定义一个名为id的Map Bean实例
    • map-class:该属性指定Spring使用哪个Map实现类来创建Bean实例。默认使用HashMap作为实现类
    • scope:指定该Map Bean实例的作用域
  • properties:该元素用于加载一份资源文件,并根据加载的资源文件创建一个Properties Bean实例。使用该标签可指定如下几个属性:
    • id:该属性指定定义一个名为id的Properties Bean实例
    • location:指定资源文件的位置
    • scope:指定该Properties Bean的作用域

示例如下:

代码详见:code\07\7.11\util

其配置文件如下:

<?xml version="1.0" encoding="GBK"?>
<!-- 指定Spring配置文件的根元素和Schema
	导入p:命名空间和util:命名空间的元素 -->
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:utilss="http://www.springframework.org/schema/util"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
	http://www.springframework.org/schema/util
	http://www.springframework.org/schema/util/spring-util-4.0.xsd">
	<!-- 配置chinese实例,其实现类是Chinese -->
	<bean id="chinese" class="org.crazyit.app.service.impl.Chinese"
		p:age-ref="chin.age" p:axe-ref="stoneAxe"
		p:schools-ref="chin.schools"
		p:axes-ref="chin.axes"
		p:scores-ref="chin.scores"/>
	<!-- 使用util:constant将指定类的静态Field定义成容器中的Bean -->
	<utilss:constant id="chin.age" static-field=
		"java.sql.Connection.TRANSACTION_SERIALIZABLE"/>
	<!-- 使用util.properties加载指定资源文件 -->
	<utilss:properties id="confTest"
		location="classpath:test_zh_CN.properties"/>
	<!-- 使用util:list定义一个List集合,指定使用LinkedList作为实现类,
	如果不指定默认使用ArrayList作为实现类 -->
	<utilss:list id="chin.schools" list-class="java.util.LinkedList">
		<!-- 每个value、ref、bean...配置一个List元素 -->
		<value>小学</value>
		<value>中学</value>
		<value>大学</value>
	</utilss:list>
	<!-- 使用util:set定义一个Set集合,指定使用HashSet作为实现类,
	如果不指定默认使用HashSet作为实现类-->
	<utilss:set id="chin.axes" set-class="java.util.HashSet">
		<!-- 每个value、ref、bean...配置一个Set元素 -->
		<value>字符串</value>
		<bean class="org.crazyit.app.service.impl.SteelAxe"/>
		<ref bean="stoneAxe"/>
	</utilss:set>
	<!-- 使用util:map定义一个Map集合,指定使用TreeMap作为实现类,
	如果不指定默认使用HashMap作为实现类 -->
	<utilss:map id="chin.scores" map-class="java.util.TreeMap">
		<entry key="数学" value="87"/>
		<entry key="英语" value="89"/>
		<entry key="语文" value="82"/>
	</utilss:map>
	<!-- 配置steelAxe实例,其实现类是SteelAxe -->
	<bean id="steelAxe" class="org.crazyit.app.service.impl.SteelAxe"/>
	<!-- 配置stoneAxe实例,其实现类是StoneAxe -->
	<bean id="stoneAxe" class="org.crazyit.app.service.impl.StoneAxe"/>
</beans>

2.4 其它Spring 其它常用的简化Schema

  暂时只用到了上面的功能,这部分详细解析待后期进行进一步深入,在此简要说明一下几个常用的简化Schema:

  • spring-aop-*.xsd:用于简化Spring AOP配置的Schema
  • spring-jee-*.xsd:用于简化Spring Java EE配置的Schema
  • spring-jms-*.xsd:用于简化Spring关于JMS配置的Schema
  • spring-lang-*.xsd:用于简化Spring 动态语言配置的Schema
  • spring-tx-*.xsd:用于简化Spring 事务配置的Schema

参考资料:

赞赏

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值