Spring 实现自定义标签解析

解析自定义标签源码:

DefaultBeanDefinitionDocumentReader#parseBeanDefinitions->delegate.parseCustomElement(ele)

 

跟踪源码可以看到,Spring 解析自定义标签时,会从 META-INF/spring.handlers 读取 handler 配置,不同的 namespace 有不同的 handler 处理方法。

handler 是一个 NamespaceHandlerSupport 的子类,需要重写 init() 并在其中注册 registerBeanDefinitionParser(name, parser)。

parser 是一个实现了 BeanDefinitionParser 接口的类,可以重写  doParse(element,builder) 其中 element 是一个 xml dom 对象,builder 是一个建造者模式对象 可以用来注册对象属性等。

​其实到这里自定义标签的解析工作就已经结束了,下面贴一个例子。

 

例子:通过如下标签,来解析一个User类

  xml 标签:

<example:user id="u1" userName="alex" email="alex@163.com" password="alex123" />

  User 类:

public class User {
    private String id;
    private String userName;
    private String email;
    private String password;

    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;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "id='" + id + '\'' +
                ", userName='" + userName + '\'' +
                ", email='" + email + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

  handler 类:

public class UserNamespaceHandler extends NamespaceHandlerSupport {

    @Override
    public void init() {
        registerBeanDefinitionParser("user", new UserBeanDefinitionParser());
    }
}

  paser 类 ,注:我这里继承的是 AbstractSimpleBeanDefinitionParser ,其提供了同名的 xml 属性 到 对象属性的设置:

public class UserBeanDefinitionParser extends AbstractSimpleBeanDefinitionParser {
    @Override
    protected Class<?> getBeanClass(Element element) {
        return User.class;
    }

    @Override
    protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
        // id 默认会当做 bean 的名称,而不是赋值给 user 对象,可以手动进行处理。
        String id = element.getAttribute("id");
        System.out.println(id);
        builder.addPropertyValue("id", element.getAttribute("id"));
        super.doParse(element, parserContext, builder);
    }
}

  resources#META-INF#spring.handlers:

http\://www.example.com/schema/user=study.yan.models.selftag.UserNamespaceHandler

  spring-context.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:example="http://www.yan.com/schema/user"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
    ">
    <example:user id="u1" userName="alex" email="alex@163.com" password="alex123" />
</beans>

  main.java,main函数中的 NoValidClassPathXmlApplicationContext 是我自定义的。为什么要自定义呢?因为默认 Spirng 启动的时候会验证 xml 格式,验证 xml 格式需要 xsd 或者 dtd文件,我们之后会加上。

public static void main(String[] args) {
  ApplicationContext cxt = new NoValidClassPathXmlApplicationContext("spring-context.xml");
  User user = (User) cxt.getBean("u1");
  System.out.println(user);
}

  NoValidClassPathXmlApplicationContext.java:

public class NoValidClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {
    public NoValidClassPathXmlApplicationContext(String configLocation) throws BeansException {
        super(configLocation);
    }

    @Override
    protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) {
        super.setValidating(false);  // 设置不需要验证
        super.initBeanDefinitionReader(reader);
    }
}

 

posted @ 2021-01-06 18:35  Super-Yan  阅读(168)  评论(0编辑  收藏  举报