Spring 创建自定义命名空间和自定义标签


共计 3785 个字符,预计需要花费 10 分钟才能阅读完成。

之前有了解过 Spirng 是如何解析第三方 xml 标签的,那么可以根据该原理写一个自定义命名空间和自定义标签,有助于我们学习其他相关框架。

接下来就自定义一个命名空间下的 mybean 标签,往容器中存放 mybean 配置的对象对象。

一、自定义命名空间和标签

通常分为以下几个步骤:

  • 1.确定命名空间名称、schema 虚拟路径、标签名称
  • 2.编写标签约束文件和映射
  • 3.编写处理器映射文件和处理器
  • 4.编写标签解析器

1. 确定相关名称和路径

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:amjun="https://www.qcyqq.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
                           https://www.qcyqq.com/amjun
                           https://www.qcyqq.com/amjun/amjun-mybean.xsd">

    <amjun:mybean id="userService" class="com.amjun.ioc4.service.impl.UserServiceImpl"/>
</beans>

这里用 xml 里面的配置文件里面的来说明以下,指定命名空间为 https://www.qcyqq.com/amjun,对应的 schema 虚拟路径为 https://www.qcyqq.com/amjun/amjun-mybean.xsd,标签名为

2. 编写标签约束文件和映射

上面指定了 schema 的虚拟路径为 https://www.qcyqq.com/amjun/amjun-mybean.xsd,所以需要在 resource 目录下的 META-INF 文件夹下新建文件 spring.schemas。

这里的目录以及文件名称都是定死的,如果不了解请参考开头说的那篇文章

spring.schemas:

http\://www.qcyqq.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="https://www.qcyqq.com/amjun"
           xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="https://www.qcyqq.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,键为命名空间虚拟路径:https://www.qcyqq.com/amjun

spring.handlers:

http\://www.qcyqq.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="https://www.qcyqq.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
                           https://www.qcyqq.com/amjun
                           https://www.qcyqq.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));
    }
}

创建容器后,可以正常在容器中获取到对象,说明整个过程没问题。

提醒:本文发布于411天前,文中所关联的信息可能已发生改变,请知悉!

Tips:清朝云网络工作室

阅读剩余
THE END