共计 3785 个字符,预计需要花费 10 分钟才能阅读完成。
之前有了解过 Spirng 是如何解析第三方 xml 标签的,那么可以根据该原理写一个自定义命名空间和自定义标签,有助于我们学习其他相关框架。
接下来就自定义一个命名空间下的 mybean 标签,往容器中存放 mybean 配置的对象对象。
一、自定义命名空间和标签
通常分为以下几个步骤:
- 1.确定命名空间名称、schema 虚拟路径、标签名称
- 2.编写标签约束文件和映射
- 3.编写处理器映射文件和处理器
- 4.编写标签解析器
1. 确定相关名称和路径
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:amjun="http://www.amjun.com/amjun"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.amjun.com/amjun
http://www.amjun.com/amjun/amjun-mybean.xsd">
<amjun:mybean id="userService" class="com.amjun.ioc4.service.impl.UserServiceImpl"/>
</beans>
这里用 xml 里面的配置文件里面的来说明以下,指定命名空间为 http://www.amjun.com/amjun
,对应的 schema 虚拟路径为 http://www.amjun.com/amjun/amjun-mybean.xsd
,标签名为
2. 编写标签约束文件和映射
上面指定了 schema 的虚拟路径为 http://www.amjun.com/amjun/amjun-mybean.xsd
,所以需要在 resource 目录下的 META-INF
文件夹下新建文件 spring.schemas。
这里的目录以及文件名称都是定死的,如果不了解请参考开头说的那篇文章
spring.schemas:
http\://www.amjun.com/amjun/amjun-mybean.xsd=com/amjun/ioc4/config/amjun-mybean.xsd
这里指定了约束文件放在 resource 目录下的 com/amjun/ioc4/config/
下,注意这里是多级目录而不是一级。
amjun-mybean.xsd:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="http://www.amjun.com/amjun"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.amjun.com/amjun">
<xs:element name="mybean">
<xs:complexType>
<xs:attribute name="id" type="xs:string" use="optional"/>
<xs:attribute name="class" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
</xs:schema>
这里定义了 mybean 标签的一些约束,比如可以配置属性 id 和 class, 但是 id 十四可选的,class 是必须的,并且类型都为字符串。
3. 编写处理器映射文件和处理器
同样,这里需要配置 spring.handlers,键为命名空间虚拟路径:http://www.amjun.com/amjun
。
spring.handlers:
http\://www.amjun.com/amjun=com.amjun.ioc4.config.AmjunNamespaceHandler
可以看见,这里指定了名称空间的处理器。
AmjunNamespaceHandler:
public class AmjunNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
this.registerBeanDefinitionParser("mybean", new MybeanBeanDefinitionParser());
}
}
自定义的处理器需要继承自 NamespaceHandlerSupport,并在初始化中注册标签解析器。
4. 编写标签解析器
MybeanBeanDefinitionParser.java
public class MybeanBeanDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
String beanName = element.getAttribute("id");
String className = element.getAttribute("class");
if (beanName.isEmpty()) {
// 如果 id 属性为空,则使用类名的作为 Bean 名称
beanName = extractClassName(className);
}
// 创建一个通用的 Bean 定义
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClassName(className);
// 将 Bean 定义注册到 Spring 的 Bean 工厂中
parserContext.getRegistry().registerBeanDefinition(beanName, beanDefinition);
return beanDefinition;
}
/**
* 获取类名
* @param fullyQualifiedClassName
* @return
*/
private String extractClassName(String fullyQualifiedClassName) {
int lastIndex = fullyQualifiedClassName.lastIndexOf('.');
if (lastIndex != -1 && lastIndex < fullyQualifiedClassName.length() - 1) {
return fullyQualifiedClassName.substring(lastIndex + 1);
}
return fullyQualifiedClassName;
}
}
标签解析器的作用是,解析每个标签配置的内容。mybean 标签的作用就是注册对象,所以会获取 id 和 class 属性,id 属性作为在容器里面的名称,class 是需要创建的对象。
因为标签中 id 是可选的,这里做了特殊处理的是,id 如果为空,就取类名作为名称。
二、自定义命名空间的使用
使用就比较简单了,只需要如下操作即可。
- 1.在配置文件中引入命名空间
- 2.在配置文件中使用自定义的标签
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:amjun="http://www.amjun.com/amjun"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.amjun.com/amjun
http://www.amjun.com/amjun/amjun-mybean.xsd">
<amjun:mybean id="userService" class="com.amjun.ioc4.service.impl.UserServiceImpl"/>
</beans>
测试文件:
public class ApplicationContextTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
System.out.println(applicationContext.getBean("userService", UserServiceImpl.class));
}
}
创建容器后,可以正常在容器中获取到对象,说明整个过程没问题。
提醒:本文发布于432天前,文中所关联的信息可能已发生改变,请知悉!