Java – Spring – 自定义XML命名空间开发
简介
在我们使用Spring时,所配置的applicationContext.xml中,我们通常都需要配置 xml 标签。本节讲解Spring是如何整合第三方XML命名空间,以及如何自定义开发XML命名空间,对XML中的Bean进行处理。
第三方XML配置
以Spring:Context标签为例,我们发现,在applicationContext.xml中可以配置Spring一些特性,如:
// 自动解析properties文件,并在xml中自由使用properties中的配置项
<context:property-placeholder location="classpath:xxx.properties" />
这是因为,xml 文件中,导入了 Spring:Context 的命名空间,以及它的约束xsd文件。
<beans
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
那么,通过引入了命名空间之后,为什么Spring能实现标签上的功能呢?
命名空间引入原理
本章节中,只讲述Spring引入结果,不过多讨论源码实现原理。
1.Spring 会对每一个jar包中定义的命名空间进行查找,并把所有的命名空间以一个 Map<String, Object> 的集合进行保存
查找 xmlns 命名空间,Spring会在每一个jar包中查找固定位置“META-INF/spring.handlers”的文件
spring:context 中的 spring.handlers 文件定义的命名空间
http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
http\://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler
http\://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler
文件中,指出当我们使用到某一个第三方命名空间中的标签时,Spring会去查找对应的第三方jar包中负责处理的全类名进行记录。
2.Spring 调用对应命名空间的处理类中的 init() 方法。
命名空间中的处理类,需要实现Spring的 NamespaceHandlerSupport 接口方法,该接口有一个 init() 方法,Spring对使用第三方命名空间标签时,会调用接口的 init() 方法,从而调用第三方命名空间的处理类,执行自定义的初始化事情。
public class ContextNamespaceHandler extends NamespaceHandlerSupport {
public ContextNamespaceHandler() {
}
public void init() {
// this.registerBeanDefinitionParser 方法是把标签和对应的解析类,存到一个 Map<String,Object> 集合中
this.registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
this.registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
this.registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
this.registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
this.registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
this.registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
this.registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
this.registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
}
}
上面的代码是 Context 的处理类中的 init() 方法,可以看出来,Context 命名空间包含了 8 个标签,每一个标签,Context 都创建了对应的标签处理类。
如 property-placeholder 为例,Context 会对 <context:property-placeholder> 标签分配了 PropertyPlaceholderBeanDefinitionParser() 解析类进行处理。
3.NamespaceHandlerSupport 中的 parser 方法定义了,把【2.】中的已注册的解析类进行调用 parser() 方法。
public BeanDefinition parse(Element element, ParserContext parserContext) {
BeanDefinitionParser parser = findParserForElement(element, parserContext);
// 调用注册好的解析类中的 parser() 方法
return (parser != null ? parser.parse(element, parserContext) : null);
}
4.从【3.】中我们可知,解析类会被 NamespaceHandlerSupport 类中的 parser() 方法所调用,所以解析类,需要实现 BeanDefinitionParser 接口
解析类 需要实现 BeanDefinitionParser 的 parser() 方法进行处理。
public final BeanDefinition parse(Element element, ParserContext parserContext) {
...
return definition;
}
上面代码是Context 对 BeanDefinitionParser 的 parser() 方法的实现,从而返回一个BeanDefinition对象。
5.META-INF/spring.schemas 文件是对 XML 约束的文件,本节暂不讲解。
自定义开发XML命名空间
步骤
1.创建 spring.handlers 文件,定义命名空间。
2.创建 spring.schemas 文件,定义xml约束(本节中该文件只创建不写约束)
3.编写命名空间处理器,UnsoftNamespaceHandle类,实现NamespaceHandlerSupport抽象类中的init()方法
4.编写标签解析器,UnsoftBeanDefinitionParser 类,实现BeanDefinitionParser接口中的parser()方法,在解析器中提交一个BeanPostProcessor类
实例
1.创建 spring.handlers 文件,定义命名空间。
http\://www.unsoft.cn/un=cn.unsoft.handles.UnsoftNamespaceHandle
2.创建 UnsoftNamespaceHandle 处理类
public class UnsoftNamespaceHandle extends NamespaceHandlerSupport {
@Override
public void init() {
this.registerBeanDefinitionParser("unsoft-anno",new UnsoftBeanDefinitionParser());
}
}
本类中,对于 <unsoft-anno> 标签进行解析,负责解析的类是 UnsoftBeanDefinitionParser
3.创建 UnsoftBeanDefinitionParser 解析类
public class UnsoftBeanDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClass(MyBeanPostProcessor.class);
// 通过 parserContext 上下文获取到 BeanDefinitionRegistry,并注册 beanDefinition 到Spring中管理
parserContext.getRegistry().registerBeanDefinition("MyBeanPostProcessor",beanDefinition);
return beanDefinition;
}
}
在 UnsoftBeanDefinitionParser 解析类中,创建了一个 postProcessor 后处理器到Spring管理中。
4.在XML中配置命名空间
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:unsoft="http://www.unsoft.cn/un"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.unsoft.cn/un http://www.unsoft.cn/unsoft.xsd">
<unsoft:unsoft-anno></unsoft:unsoft-anno>
</bean>
共有 0 条评论