谈谈 Spring xml 配置文件中的命名空间,以及一些例外情况
导言
在平时的开发中,我们习惯于复制xml文件,而且能够奏效。但你有没有想过,这里面的元素都是什么含义呢?今天,我们就聊聊其中的命名空间以及一些例外情况,希望能够拓展一些知识点。
我们来看一个简单的配置文件:
第一个问题:你知道里面的xmlns和xsi是什么意思吗?
xmlns和xsi
最容易记住的方式,是理解它们的英文全称:
xmlns:xml namespace,也就是xml命名空间的意思。
xsi:XMLSchema-instance,取的其中三个单词首字母,分别是xml的“x”,schema的“s”,instance的“i”。也就是xml元素的定义文件,我们可以通过属性schemaLocation可以指定命名空间对应的xsd文件(xsd文件用于定义元素的组织形式,可以参见:https://www.cnblogs.com/newsouls/archive/2011/10/28/2227765.html)。
注意,xmlns和xsi:schemaLocation一般是对应的(记住这里的“一般”,因为有例外,后面讲),比如:
命名空间“http://www.springframework.org/schema/beans”,对应的是“http://www.springframework.org/schema/beans/spring-beans.xsd”。我们可以点进去这个文件看beans的各个属性。
命名空间“http://www.springframework.org/schema/aop”,对应的是“http://www.springframework.org/schema/aop/spring-aop.xsd”。
我们也可以自定义自己的命名空间和对应的xsd文件。
其中,xmlns:aop的aop是命名空间的名字,其他xmlns:task同理。但beans对应的命名空间是默认的,前面的“<beans”已经指明了,因此也就不能写成xmlns:beans了。
Spring配置文件的一些例外
仔细观察上面的文件,我们可以发现,有两个命名空间没有对应的xsd文件:
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
这两个命名空间分别对应构造器参数和属性。举个例子:我们定义三个bean;其中名为x的bean,通过构造器传入y,通过属性传入z:
此时配置文件可以这样写:
其中,第21行的c就对应于第8行定义的c命名空间,p命名空间同理。
那么第二个问题来了:它们的xsd文件哪去了?
带着问题,我们搜索“xmlns:p="http://www.springframework.org/schema/p"”,得到结果:
In spring, p-namespace is the XML short cut to inject dependency in bean. p-namespace replaces <property> tag of XML. and it only exits in core of spring. We can directly assign the attribute name of the class with p-namespace within bean tag. We can use p-namespace in place of <property> tag in spring XML.
好了,我们现在知道它们没有对应的xsd文件,那么Spring是怎么解析的呢?
我们可以尝试全局搜索"www.springframework.org/schema/p",可以发现它配置在spring-beans包的META-INF文件夹下的spring.handlers文件中:
该文件记录了命名空间及其对应的handler。可以想到:handler会在bean的处理过程中解析对应的值。下面我们以c命名空间看看Spring是怎么解析的。
先写入口类,然后调试即可:
我们可以看到,经过一系列xml文件的解析步骤,最终进到了org.springframework.beans.factory.xml.BeanDefinitionParserDelegate中:
其中的node已经走到了c:y-ref这一步。从下图可以看到bean的一些属性都是保存在arrtibutes字段中的。每个属性又是一个node,最终会走到上面说的类中进行decorate,也就是装饰。
继续深入:
我们会发现第1444行取出了当前的命名空间,第1446行会取出spring.handles文件中定义的org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandler。
具体地,先读取spring.handlers,获取所有的handlers并放到map中(注意,不只是spring-beans包下面的spring.handlers,其他包里面的spring.handlers也会被搜索),再根据key(也即命名空间)取出对应的handler
取到具体的handler后,会进到decorate中,将对应的值注入进去:
其他handler同理,不再赘述。
扩展
每个命名空间都有对应的handler(或处理机制)。p和c两个命名空间没有对应的xsd的原因,可能是因为其语法比较简单,没有必要专门定义xsd吧。
总结
本文内容分为两块。
首先,介绍了Spring xml配置文件中的一些命名空间含义。其实这是xml文件的概念,并非Spring的特性。
然后,我们介绍了p命名空间和c命名空间这两种没有xsd文件的例外情况,并通过跟踪源码了解它们的执行原理。
版权声明: 本文为 InfoQ 作者【xiaoxi666】的原创文章。
原文链接:【http://xie.infoq.cn/article/fca9d64b717af3777b5b570d2】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论