spring内幕(十一)spring自定义命名空间

在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>

类型定义 属性名称是name type是string


		
			
				
			
		
		
			
				
			
		
		
			
				
			
		
	

加起来就定义了一个元素叫lxx 然后有id name package属性

2.然后把这个文档引入到spring的xml里面去 就可以使用了
spring内幕(十一)spring自定义命名空间_第1张图片

但是此时 这个标签 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目录下
spring内幕(十一)spring自定义命名空间_第2张图片

然后编译打包。验证一下
spring内幕(十一)spring自定义命名空间_第3张图片
可以看到 属性值已经获取到了 而且bean也实例化了
在这里插入图片描述

你可能感兴趣的:(spring源码学习专栏)