Spring 框架从 2.0 版本开始,提供了基于 Schema 风格的 XML 扩展机制,允许开发者扩展最基本的 Spring 配置文件(一般是 classpath 下的 spring.xml)。
试想一下,如果我们直接在 spring.xml 中加入一个自定义标签
现在我们来看下怎么实现这个功能,可以参考 Spring 帮助文档中的 extensible-xml.html。我们知道如果在需要在 spring.xml 中配置数据源,需要进行如下的配置:
1
2
3
4
5
6
| < bean id = "dataSource" class = "org.apache.commons.dbcp.BasicDataSource" > < property name = "driverClassName" value = "com.mysql.jdbc.Driver" /> < property name = "username" value = "root" /> < property name = "password" value = "1234" /> </ bean > |
1
2
| < aty:datasource id = "myDataSourcce" |
1. 提供一个 xsd 文件,负责对 xml 的标签
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| <? xml version = "1.0" encoding = "UTF-8" ?> elementFormDefault = "qualified" attributeFormDefault = "unqualified" > < xsd:element name = "datasource" > < xsd:complexType > < xsd:complexContent > < xsd:extension base = "beans:identifiedType" > < xsd:attribute name = "url" type = "xsd:string" use = "required" /> < xsd:attribute name = "userName" type = "xsd:string" use = "required" /> < xsd:attribute name = "password" type = "xsd:string" use = "required" /> </ xsd:extension > </ xsd:complexContent > </ xsd:complexType > </ xsd:element > </ xsd:schema > |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
| package net.aty.custom.define; import net.aty.custom.cfg.DataSourceInfo; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.w3c.dom.Element; public class DatasourceBeanDefinitionParser implements BeanDefinitionParser { public BeanDefinition parse(Element element, ParserContext context) { RootBeanDefinition def = new RootBeanDefinition(); // 设置Bean Class def.setBeanClass(DataSourceInfo. class ); // 注册ID属性 String id = element.getAttribute( "id" ); BeanDefinitionHolder idHolder = new BeanDefinitionHolder(def, id); BeanDefinitionReaderUtils.registerBeanDefinition(idHolder, context.getRegistry()); // 注册属性 String url = element.getAttribute( "url" ); String userName = element.getAttribute( "userName" ); String password = element.getAttribute( "password" ); BeanDefinitionHolder urlHolder = new BeanDefinitionHolder(def, url); BeanDefinitionHolder userNameHolder = new BeanDefinitionHolder(def, userName); BeanDefinitionHolder passwordHolder = new BeanDefinitionHolder(def, password); BeanDefinitionReaderUtils.registerBeanDefinition(urlHolder, context.getRegistry()); BeanDefinitionReaderUtils.registerBeanDefinition(userNameHolder, context.getRegistry()); BeanDefinitionReaderUtils.registerBeanDefinition(passwordHolder, context.getRegistry()); def.getPropertyValues().addPropertyValue( "url" , url); def.getPropertyValues().addPropertyValue( "userName" , userName); def.getPropertyValues().addPropertyValue( "password" , password); return def; } } |
3. 定义个 NamespaceHandler,由 Sping 框架的调用入口。这也是我们自定义 xml 解析的入口
1
2
3
4
5
6
7
8
9
10
| package net.aty.custom.define; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; public class DatasourceNamespaceHandlerSupport extends NamespaceHandlerSupport { @Override public void init() { registerBeanDefinitionParser( "datasource" , new DatasourceBeanDefinitionParser()); } } |
Spring 没那么聪明,它无法知道我们在什么地方定义了哪些扩展标签,这些标签将被谁解析,怎么解析。这个过程要我们通过一些配置文件来告知 Spring 知道,它们就是 spring.handlers 和 spring.schemas,它们放在 META-INF 目录中。Spring.jar 的 META-INF 目录中也有同名的文件,它们的文件内容基本上是相似的,而 Spring 在执行过程中,如果发现其他 jar 文件的 META-INF 文件夹中包含有这两个文件,Spring 将会合并它们。
spring.handlers 内容如下:
1
| http\://www.aty.com/schema/aty=net.aty.custom.define.DatasourceNamespaceHandlerSupport |
1
| http\://www.aty.com/schema/aty.xsd=aty.xsd |
测试工程的 spring.xml 配置如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
| <? xml version = "1.0" encoding = "UTF-8" ?> xsi:schemaLocation="http://www.springframework.org/schema/beans < aty:datasource id = "myDataSourcce" </ beans > |
1
2
3
4
5
6
7
8
9
10
11
12
13
| import net.aty.custom.cfg.DataSourceInfo; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestMain { private static ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( "spring.xml" ); public static void main(String[] args) { DataSourceInfo d = (DataSourceInfo) context.getBean( "myDataSourcce" ); System.out.println(d); } } |
转载请并标注: “本文转载自 linkedkeeper.com (文/张松然)”