首页 > 编程语言 > 详细

Spring 源码解析之 自定义标签解析

时间:2020-09-27 21:28:30      阅读:40      评论:0      收藏:0      [点我收藏+]

上篇博客我们讲到,spring在做xml解析的时候,将xml中的各种属性,都封装到一个GenericBeanDefinition对象中,那么在将xml标签进行解析的时候,会出现两种情况,一种是针对传统(默认)标签的解析,而spring也提供了另外一种自定义标签的解析。

首先我们先来看个自定义的例子。

/**
 * @author monco
 * @data 2020/9/27 15:28
 * @description :自定义需要注入到spring的对象
 */
public class CustomUser {

    private String id;

    private String username;

    private String email;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}
/**
 * @author monco
 * @data 2020/9/27 15:37
 * @description : 解析自定义标签 custom
 */
public class MyNamespaceHandler extends NamespaceHandlerSupport {

    @Override
    public void init() {
        registerBeanDefinitionParser("custom", new UserBeanDefinitionParser());
    }
}
/**
 * @author monco
 * @data 2020/9/27 15:32
 * @description : 将xml中读取的标签 放入到 BeanDefinition 中
 */
public class UserBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {

    protected Class getBeanClass(Element element) {
        return CustomUser.class;
    }

    protected void doParse(Element element, BeanDefinitionBuilder builder) {
        String username = element.getAttribute("username");
        String email = element.getAttribute("email");
        if (StringUtils.hasText(username)) {
            builder.addPropertyValue("username", username);
        }
        if (StringUtils.hasText(email)) {
            builder.addPropertyValue("email", email);
        }
    }
}

我们在代码层面需要做的事就是三步,第一步,定义一个需要注册的bean,第二步,将xml中解析的元素转化成BeanDefinition,第三步,将BeanDefinition注册到spring容器中,交给spring容器管理。

下面我们需要配置一些其他的东西。请睁大眼睛 仔细观察。

技术分享图片

 

 

 我们需要在resources文件夹下,创建META-INF文件夹,在其中创建3个文件,一个xsd文件,一个handlers文件,一个schemas文件。

xsd 文件

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.monco.com/schema/mytags"
            xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.monco.com/schema/mytags"
            elementFormDefault="qualified">
    <!--自定义标签的名字 叫 custom-->
    <xsd:element name="custom">
        <xsd:complexType>
            <xsd:attribute name="id" type="xsd:string"></xsd:attribute>
            <xsd:attribute name="username" type="xsd:string"></xsd:attribute>
            <xsd:attribute name="email" type="xsd:string"></xsd:attribute>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>

handlers 文件 指定读取的 id namespace

http\://www.monco.com/schema/mytags=com.monco.bean.custom.MyNamespaceHandler

schemas 文件 指定读取的xsd 位置

http\://www.monco.com/schema/mytags.xsd=META-INF/mytags.xsd

spring.xml 文件 

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.monco.com/schema/mytags
    http://www.monco.com/schema/mytags.xsd
"
       xmlns:monco="http://www.monco.com/schema/mytags"
       default-lazy-init="false">

    <!--自定义标签-->
    <context:component-scan base-package="com.monco"/>

    <!--传统标签-->
    <bean class="com.monco.entity.User" id="user">
        <constructor-arg name="username" value="monco"/>
        <constructor-arg name="password" value="123456"/>
    </bean>

    <!--replace-method-->
    <bean id="replaceClass" class="com.monco.bean.ReplaceClass" lazy-init="false"/>
    <bean id="originClass" class="com.monco.bean.OriginClass">
        <replaced-method name="method" replacer="replaceClass">
            <!--方法可能出现重载的情况,要根据类型和方法名找方法-->
            <arg-type match="java.lang.String"/>
        </replaced-method>
    </bean>

    <monco:custom id="customUser" username="monco" email="18552193820@163.com"/>

</beans>

测试类 

 @Test
    public void testCustomTag() {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        CustomUser customUser = (CustomUser) applicationContext.getBean("customUser");
        System.out.println(customUser.getUsername());
    }

运行结果

技术分享图片

 

 

通过上述一个简单的例子,我们可以发现,我们自己定义的Bean竟然奇迹般的被解析到了。现在我们就来分析下,这是why?这些配置文件的作用到底是啥?我们学了这些东西到底有啥用?

上节我们讲到  DefaultBeanDefinitionDocumentReader 中的 parseBeanDefinitions 的方法

技术分享图片

 

我们发现在实际去解析自定义标签的第一步,就是将元素中的namespaceURI读取出来,读取到 namespaceURI 之后,我们就可以 handlers 文件找到对应的 处理类

技术分享图片

 

通过 文件 来找到处理类的这个过程 我们暂且称之为 SPI 思想。

技术分享图片

 

我们通过上述步骤可以解决根据namespace 找到对应的处理类,接下来,我们需要执行 parse() 方法,将对应的标签写入BeanDefinition就可以了。主要是SPI的思想。

具体可以参考 这篇博客

下一节主要介绍,将xml解析到Bean 中,接下来的重点是 怎样加载这个Bean。

 

Spring 源码解析之 自定义标签解析

原文:https://www.cnblogs.com/monco-sxy/p/13741241.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!