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>

 

 

如果您喜欢本站,点击这儿不花一分钱捐赠本站

这些信息可能会帮助到你: 下载帮助 | 报毒说明 | 进站必看

修改版本安卓软件,加群提示为修改者自留,非本站信息,注意鉴别

THE END
分享
二维码
打赏
海报
Java – Spring – 自定义XML命名空间开发
简介 在我们使用Spring时,所配置的applicationContext.xml中,我们通常都需要配置 xml 标签。本节讲解Spring是如何整合第三方XML命名空间,以及如何自定义开发XML命名空间,对XML中的Bean进……
<<上一篇
下一篇>>