在spring的xml配置中
有形如http://www.springframework.org/schema/context 形式的url链接
这个是spring用来定义各种标签用的 ,同时各种第三方和spring集成的框架 比如说dubbo mybatis等 也有自己的命名空间,这些也叫自定义命名空间。
是spring里面一个很重要的设计,给第三方应用留足了充分的拓展。
如果要自己定一个标签 且能让spring解析到 ,要如何做呢?
目的:
要实现的一个自定义标签 标签名字叫lxx 属性有id name package
效果是将TestBean注入到spring容器中,并被name和package赋值
标签形如
<test:lxx id="lxx" name="test" package="com.lxx.ContextDemo"></test:lxx>
TestBean如下
public class TestBean {
private String name;
private String basePackage;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPackage() {
return basePackage;
}
public void setPackage(String basePackage) {
this.basePackage = basePackage;
}
@Override
public String toString() {
return "{" +
"name='" + name + '\'' +
", basePackage='" + basePackage + '\'' +
'}';
}
}
1.首先在resource目录下的META-INF文件下创建spring.schemas文件
并放入命名空间url和对应的xsd文件的地址
http\://lxx.test.com/schema/lxx/lxx-1.0.xsd=./lxx/config/lxx-1.0.xsd
xsd文件也是一个xml文件,但是这是一个用来对xml文件进行约束的xml文件
spring2.0版本用的是dtd文件 现在已经不用了
创建lxx-1.0.xsd文件,然后里面定义标签的名字 属性名 属性类型
这里定义的命名空间namespace是 http://lxx.test.com/schema/lxx
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://lxx.test.com/schema/lxx"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://lxx.test.com/schema/lxx">
<xsd:complexType name="lxxType">
<xsd:attribute name="id" type="xsd:ID">
<xsd:annotation>
<xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="name" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[ The name of bean. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="package" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[ The scan package. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:element name="lxx" type="lxxType">
<xsd:annotation>
<xsd:documentation><![CDATA[ The annotation config ]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:schema>
解释:
element name=“lxx” 元素名称是lxx 类型是lxxType
<xsd:element name="lxx" type="lxxType">
<xsd:annotation>
<xsd:documentation><![CDATA[ The annotation config ]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
类型定义
加起来就定义了一个元素叫lxx 然后有id name package属性
2.然后把这个文档引入到spring的xml里面去 就可以使用了
但是此时 这个标签 spring在执行加载时候是认不出来的。
所以还需要定义解析器
我们定义的命名空间是http://lxx.test.com/schema/lxx
该namespace还需要对应一个解析器 ,该解析继承NamespaceHandlerSupport接口
在init方法中注册BeanDefinitionParser
public class LxxNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
// 注册一个自定义的解析器, 用于解析命名空间下的annotation节点
registerBeanDefinitionParser("lxx", new TestDefinitionParser());
}
}
然后创建一个名字叫TestDefinitionParser的BeanDefinitionParser,这个里面就是真正解析和处理自定义标签的逻辑
public class TestDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClass(TestBean.class);
MutablePropertyValues mutablePropertyValues = beanDefinition.getPropertyValues();
// 添加name属性
if (element.hasAttribute("name")) {
mutablePropertyValues.addPropertyValue("name", element.getAttribute("name"));
}
// 添加package属性
if (element.hasAttribute("package")) {
mutablePropertyValues.addPropertyValue("package", element.getAttribute("package"));
}
String id = element.getAttribute("id");
// 拿到注册表, 注册BeanDefinition
parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
return beanDefinition;
}
}
以上是获取TestBean.class 并将读取到的属性值设置到beanDefinition里面去,BeanDefinitionParser的parse方法的作用就是解析xml的标签属性 返回一个BeanDefinition (bean的定义信息)
命名空间和namespacehandler和BeanDefinitionParser都有了 ,然后spring怎么知道呢?
需要在resource目录下的META-INF文件夹下 建立spring.handler文件
并将命名空间和对应的handler以key=value的形式写入
此时 在METE-INF目录下