欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring中xml自定义标签的实现流程

程序员文章站 2024-03-22 13:51:52
...

Spring中xml自定义标签的实现流程

背景
虽然xml方式在现在看来有一些落后了,但毕竟是注解的一种过渡。而解析器不管是注解还是xml都是一致的。

例如:dubbo大量的自定义标签,包括spring中也存在大量的标签(低版本xml方式),那么自定义标签在Spirng中是如何实现的,今天就来理一下流程。


一、实现步骤先知

  1. 编写一个XSD: 定义需要使用到的标签
  2. 编写一个解析标签的BeanDefinitionParse: 解析这些标签,将会做什么操作
  3. 编写一个Handler,将自定义的BeanDefinitionParse进行注册: 将其注册到Map集合中。
  4. 编写spring.handlers 和 spring.schemas 两个文件:分别告诉handler 和 schema的位置。
  5. 编写一个应用程序验证

二、自定义标签实现

模拟<context:component-scan/> 实现注解扫描操作;实现标签<uzong:component-scan/>
话不多说,直接开始吧

工程结构如下:
Spring中xml自定义标签的实现流程


2.1 编写xsd

模拟context,编写一份自己的xsd。名称:uzong.xsd

<?xml version="1.0" encoding="UTF-8"?>

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
		targetNamespace="http://www.springframework.org/schema/uzong"
		elementFormDefault="qualified">
	<xsd:element name="component-scan">
		<xsd:complexType>
			<xsd:attribute name="base-package" type="xsd:string">
				<xsd:annotation>
					<xsd:documentation><![CDATA[
			The comma/semicolon/space/tab/linefeed-separated list of packages to scan for annotated components.
							]]></xsd:documentation>
				</xsd:annotation>
			</xsd:attribute>
		</xsd:complexType>
	</xsd:element>
</xsd:schema>

关键元素:base-package;指定路径包名


2.2 编写自己的parse

下面的代码主要逻辑就是获取basePackage路径,然后使用ClassPathBeanDefinitionScanner 进行扫描注解。关于扫描器的使用不是本篇重点,可以跳过。


public class UzongComponentScanBeanDefinitionParse implements BeanDefinitionParser {

	@Override
	public BeanDefinition parse(Element element, ParserContext parserContext) {
		//1. 获取value
		String basePackage = element.getAttribute("base-package");//仅解析:base-package
		//2. 解析获取basePackage
		basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
		// 3. 字符串分割
		String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
				ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
		//4. 获取扫描器
		ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), true);
		//5. 扫描注册
		scanner.scan(basePackages);
		return null;
	}

	protected ClassPathBeanDefinitionScanner createScanner(XmlReaderContext readerContext, boolean useDefaultFilters) {
		return new ClassPathBeanDefinitionScanner(readerContext.getRegistry(), useDefaultFilters,
				readerContext.getEnvironment(), readerContext.getResourceLoader());
	}

}

在完成了我们的parse后,需要编写Handler来注册parse到Spring的集合中


2.3 注册handler 到集合

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

public class UzongContextNamespaceHandler extends NamespaceHandlerSupport {
	@Override
	public void init() {
		registerBeanDefinitionParser("component-scan",new UzongComponentScanBeanDefinitionParse());
	}
}

registerBeanDefinitionParser 实质就是将其放入map中;NamespaceHandlerSupport 中的parsers


2.4 spring.handlers 和 spring.schemas

spring.handlers

http\://www.springframework.org/schema/uzong=uzong.parse.UzongContextNamespaceHandler

spring.schemas

http\://www.springframework.org/schema/uzong.xsd=META-INF/uzong.xsd

完成上面步骤后,基本上已经完成自定义标签的实现流程了,接下进行验证


2.5 验证

编写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:uzong="http://www.springframework.org/schema/uzong"
	   xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		   http://www.springframework.org/schema/uzong http://www.springframework.org/schema/uzong.xsd">
		   
	<uzong:component-scan base-package="uzong.parse"/>

</beans> 

其中Apple 为一个bean

@Component
public class Apple {
	private String name = "apple";

	public Apple() {
	}

	@Override
	public String toString() {
		return "Apple{" +
				"name='" + name + '\'' +
				'}';
	}

	public Apple(String name) {
		this.name = name;
	}
}
public class App {

	public static void main(String[] args) {
		ApplicationContext ac = new ClassPathXmlApplicationContext("application-uzong.xml");
		// 从容器中获取bean
		Apple apple = (Apple) ac.getBean("apple");
		System.out.println(apple);
	}
}

运行结果如下:

Apple{name='apple'}

2.6 小结

通过以上几个步骤,就完成了自定义标签的实现流程。不过这种xml的方式是否已经比较过时了;现在多采用注解方式。但是,注解和xml的解析本质都是一样的。重点都是在parse这个类上面。

相关标签: Spring 的故事