一:概述
在很多情况下,我们需要为系统提供可配置化支持,简单的做法可以直接基于Spring的标准Bean来配置,但配置较为复杂或者需要更多丰富控制的时候,就会显得非常笨拙。一般的做法是用原生态的方式去解析定义好的XML文件,然后转为可配置对象。这种方式可以解决问题,但是实现起来比较繁琐。但是利用Spring 提供了可扩展的Schema,将会非常方便。同样,像Spring自身组件tx,阿里的dubbo也同样是利用了可扩展的schema。
创建Spring自定义标签通常需要一下几个步骤:
- 定义自己所要扩展的组件。
- 定义一个XSD文件。
- 创建一个类,实现BeanDefinitionParser接口,用来解析XSD文件中定义的组件。
- 创建一个Handler,实现NamespaceHandlerSupport,将组件注册到Spring容器中去。
- 编写spring.handlers和spring.schemas文件。
如下,我们就根据上门步骤一步步实现我们自定义标签的过程。
(1)创建我们所要扩展的组件,本博文用简单的pojo User类代替,如图所示:
(2)编写XSD文件,XSD是XML Schema Definition的缩写,不知道该语法的可自行去w3c学习相关语法,这里推荐一篇博客(xsd文档解释),博主感觉还是蛮不错的,如图,为编写xsd文件。
(3)实现BeanDefinitionParser
public class UserBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected Class getBeanClass(Element element) {
return User.class;
}
@Override
protected void doParse(Element element, BeanDefinitionBuilder builder) {
String userName = element.getAttribute("userName");
String email = element.getAttribute("email");
if(StringUtils.hasText(userName)){
builder.addPropertyReference("userName",userName);
}
if(StringUtils.hasText(email)){
builder.addPropertyValue("email",email);
}
}
}
(4)扩展NamespaceHandlerSupport接口
/**
* 扩展 namespaceHandlerSupport借口,将自己的组件注册到spring容器中去
*
* @author chenhongwei
* @date 2019/3/3 17:45
**/
public class CustomerNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("user", new UserBeanDefinitionParser());
}
}
(5)编写spring.handlers和spring.schemas文件.
如上图所示,该两个文件全都在 META-INF目录i下,其中spring.schemas是告诉spring容器我们的自定义的xsd文件在哪里。
二:测试
自此,自定义标签的步骤已完成,编写测试用例验证
(1) 编写Spring配置文件:
<?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:myname="http://www.chw.com/schema/user"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.chw.com/schema/user http://www.chw.com/schema/user.xsd">
<myname:user id="testBean" email="bbb"/>
</beans>
(2)编写测试类:
ApplicationContext cxt = new ClassPathXmlApplicationContext("customer-tag-spring.xml");
User user = (User) cxt.getBean("testBean");
System.out.println(user);
测试结构截图:
可以看到,我们自己自定义的组件已经被注册到Spring容器中去了。对于Spring容器的解析过程,后续也会有文章进行专门解释。