有一些基于Spring的框架通常会提供他们自己特有的一些配置方式,
最常见的莫过于基于Spring的XML扩展方式, 定义一套自己风格的bean定义语法,
来让一些配置与框架的语义更加的贴近。 比如说,下面的这样的配置:
<dubbo:service id="memberService" ref="memberService.local" version="${dubbo.memberService.version}" interface="com.xxxx.morgan.member.MemberService" />
这篇文章主要用来记录一下,如何基于Spring来扩展自己想要的语义标签。
从Spring2.0开始,Spring提供了XML Schema可扩展机制,用户可以自定义XML Schema文件,并自定义XML Bean解析器,并集成到Spring Ioc 容器中。
完成XML自定义扩展,需要下面几个步骤
- 创建一个 XML Schema 文件,描述自定义的合法构建模块,也就是xsd文件
- 自定义个处理器类,并实现NamespaceHandler接口(比较容易)
- 自定义一个或多个解析器,实现BeanDefinitionParser接口(最关键的部分)
- 注册上面的组件到Spring IOC容器中
这里用一个简单的例子来说明下整个步骤:
我们需要完成一个这样的标签定义:
<calculator:calculator id="cal" operator="add" number2="234" number1="40.5" />
最终我们需要通过如下调用,达到输出的目的:
Calculator ca=(Calculator)ctx.getBean("cal"); System.out.println(ca.getOperator()+"-"+ca.getResult());
最终输出: add-274.5
自定义 XML Schema 文件
xsd描述文件
<?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns="http://ivanzhangwb.com/custom/schema/calculator" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:beans="http://www.springframework.org/schema/beans" targetNamespace="http://xttblog.com/custom/schema/calculator" elementFormDefault="qualified" attributeFormDefault="unqualified"> <xsd:import namespace="http://www.springframework.org/schema/beans" /> <xsd:element name="calculator"> <xsd:complexType> <xsd:complexContent> <xsd:extension base="beans:identifiedType"> <xsd:attribute name="number1" type="xsd:decimal" /> <xsd:attribute name="number2" type="xsd:decimal" /> <xsd:attribute name="operator" type="xsd:string" /> </xsd:extension> </xsd:complexContent> </xsd:complexType> </xsd:element> </xsd:schema>
其中自定义的命名空间是http://xttblog.com/custom/schema/calculator,定义了calculator元素,属性有number1,number2,operator
实现 NamespaceHandlerSupport 接口,定义解析行为
public class CalculatorNameSpaceSupport extends NamespaceHandlerSupport { public void init() { registerBeanDefinitionParser("calculator",new CalculatorBeanDefinitorParse()); } }
实现 AbstractSingleBeanDefinitionParser 接口
public class CalculatorBeanDefinitorParse extends AbstractSingleBeanDefinitionParser { @Override protected Class getBeanClass(Element element) { return Calculator.class; } @Override protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { String operator = element.getAttribute("operator"); Assert.notNull(operator, "operaotr is required."); if (StringUtils.hasText(operator)) { builder.addPropertyValue("operator", operator); if ("add".equalsIgnoreCase(operator)) { processAdd(element, builder); } else if ("minus".equalsIgnoreCase(operator)) { processMinus(element, builder); } else { throw new UnsupportedOperationException("UnSupport Operaotr"); } } } private void processAdd(Element element, BeanDefinitionBuilder builder) { try { builder.addPropertyValue("result",new BigDecimal((String) assertAttributeNotNull(element, "number1")) .add(new BigDecimal((String) assertAttributeNotNull(element,"number2")))); } catch (Exception e) { throw new IllegalArgumentException("Number1/Number2 Must be Number."); } } private Object assertAttributeNotNull(Element element, String attributeName) { String attribute = element.getAttribute(attributeName); return StringUtils.hasText(attribute) ? StringUtils.trimWhitespace(attribute) : ""; } private void processMinus(Element element, BeanDefinitionBuilder builder) { try { builder.addPropertyValue("result", new BigDecimal((String) assertAttributeNotNull(element, "number1")).divide(new BigDecimal( (String) assertAttributeNotNull(element, "number2")))); } catch (Exception e) { throw new IllegalArgumentException("Number1/Number2 Must be Number."); } } }
注册 handler 和 schema
为了让Spring在解析xml的时候能够感知到我们的自定义元素,我们需要把namespaceHandler和xsd文件放到2个指定的配置文件中,这2个文件都位于META-INF目录中
文件: spring.handlers
http/://xttblog.com/custom/schema/calculator=com.ivanzhangwb.calculator.parse.CalculatorNameSpaceSupport
文件:spring.schemas
http/://ivanzhangwb.com/custom/schema/calculator.xsd=META-INF/calculator.xsd
配置完成之后,我们就可以在spring配置文件中使用我们自定义的标签了。
Spring 配置文件引用自定义标签
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:calculator="http://ivanzhangwb.com/custom/schema/calculator" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://xttblog.com/custom/schema/calculator http://xttblog.com/custom/schema/calculator.xsd"> <calculator:calculator id="cal" number1="40.5" number2="234" operator="add" /> </beans>
对自定义标签进行单元测试
public class XMLSchemaCustomTest{ public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); Calculator ca=(Calculator)ctx.getBean("cal"); System.out.println(ca.getOperator()+"-"+ca.getResult()); } }
: » Spring可扩展的XML Schema的自定义标签详解
原创文章,作者:306829225,如若转载,请注明出处:https://blog.ytso.com/251479.html