Spring的自定义标签
当Spring拿到一个元素时首先要做的是根据命名空间进行解析,如果是默认的命名空间,则使用parseDefaultElement方法进行元素解析,否则使用parseCustom Element方法进行解析。
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } } public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) { String namespaceUri = getNamespaceURI(ele); NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler == null) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); return null; } return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); }
自定义标签的使用
扩展Spring自定义标签配置大致需要以下几个步骤(前提是要把Spring的Core包加入项目中)。
- 创建一个需要扩展的组件。
- 定义一个XSD文件描述组件内容。
- 创建一个文件,实现BeanDefinitionParser接口,用来解析XSD文件中的定义和组件定义。
- 创建一个Handler文件,扩展自NamespaceHandlerSupport,目的是将组件注册到Spring容器。
- 编写Spring.handlers和Spring.schemas文件。
现在我们就按照上面的步骤一步步地体验自定义标签的过程。
第一步:
public class TestBean { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "TestBean{" + "name='" + name + '\'' + '}'; } }
第二步:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <xsd:schema xmlns="http://code.alibabatech.com/schema/dubbo" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://code.alibabatech.com/schema/dubbo"> <xsd:element name="custom" type="customType"> </xsd:element> <xsd:complexType name="customType"> <xsd:attribute name="id" type="xsd:ID"> </xsd:attribute> <xsd:attribute name="name" type="xsd:string"> </xsd:attribute> </xsd:complexType> </xsd:schema>
第三步:
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.w3c.dom.Element; public class TestCustomBeanDefinitionParser implements BeanDefinitionParser { public BeanDefinition parse(Element element, ParserContext parserContext) { String id = element.getAttribute("id"); String name = element.getAttribute("name"); RootBeanDefinition beanDefinition = new RootBeanDefinition(); beanDefinition.setBeanClass(TestBean.class); beanDefinition.getPropertyValues().addPropertyValue("name", name); parserContext.getRegistry().registerBeanDefinition(id, beanDefinition); return beanDefinition; } }
第四步:
import org.springframework.beans.factory.xml.NamespaceHandlerSupport; public class TestNamespaceHandler extends NamespaceHandlerSupport { public void init() { registerBeanDefinitionParser("custom", new TestCustomBeanDefinitionParser()); } }
第五步:
spring.handlers:
http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler
spring.schemas:
http\://code.alibabatech.com/schema/dubbo/dubbo.xsd=META-INF/dubbo.xsd
第六步:
<?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:dubbo="http://code.alibabatech.com/schema/dubbo" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <dubbo:custom id="testCustom" name="this is a test custom tag" /> </beans> import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { String xml = "classpath:test.xml"; ApplicationContext context = new ClassPathXmlApplicationContext(new String[] { xml }); System.out.println(context.getBean("testCustom")); } } 上例输出为: TestBean {name=this is a test custom tag}