Spring中xml自定義標籤的實現流程
背景:
雖然xml方式在現在看來有一些落後了,但畢竟是註解的一種過渡。而解析器不管是註解還是xml都是一致的。
例如:dubbo大量的自定義標籤,包括spring中也存在大量的標籤(低版本xml方式),那麼自定義標籤在Spirng中是如何實現的,今天就來理一下流程。
一、實現步驟先知
- 編寫一個XSD: 定義需要使用到的標籤
- 編寫一個解析標籤的BeanDefinitionParse: 解析這些標籤,將會做什麼操作
- 編寫一個Handler,將自定義的BeanDefinitionParse進行註冊: 將其註冊到Map集合中。
- 編寫spring.handlers 和 spring.schemas 兩個文件:分別告訴handler 和 schema的位置。
- 編寫一個應用程序驗證
二、自定義標籤實現
模擬<context:component-scan/>
實現註解掃描操作;實現標籤<uzong:component-scan/>
話不多說,直接開始吧
工程結構如下:
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這個類上面。