Spring 配置文件xml 是可以通過註冊命名空間來達到解析擴展的。也就是說 AOP、TX、等都是通過擴展命名空間來解析數據的。定義自己的命名解析需要有幾個步驟,主要採用策略模式進行開發,Github實例代碼:https://github.com/JerryDai90/java-case/tree/master/spring/xml-extension
1. 自定義 DefinitionParser
需要定義解析 xml DefinitionParser
,如 ConfigBeanDefinitionParser.java
2、定義 Handler
定義 Handler
,此類用於註冊到 Spring
處理類池裏面,裏面需要在 init 方法中註冊實現類。
比如AOP就定義了
config
、aspectj-autoproxy
、scoped-proxy
、spring-configured
這些元素就使用
public class AopNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
// In 2.0 XSD as well as in 2.1 XSD.
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
// Only in 2.0 XSD: moved to context namespace as of 2.1
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
}
3. 定義 xml 命名空間
比如AOP 的命名空間 xmlns:aop="http://www.springframework.org/schema/aop"
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
與 DSD 文件定義
4、添加 spring.handlers、spring.schemas 文件
需要在MATE-INF 中 增加 spring.handlers 文件。命名空間需要指定 Handler 類。
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
需要在MATE-INF 中 增加 spring.schemas 文件,對應命名空間對應的xsd文件。
5. 關鍵類
DefaultNamespaceHandlerResolver:解析加載到ClassLoader裏面的 spring.handlers 文件。
NamespaceHandlerSupport:註冊標籤對應的解析類
6. 小結
這樣就可完成擴展Spring xml 的解析並且實現相應的業務。大概劃的處理圖。標準的配置流程可以參考 spring-aop-5.2.3.RELEASE.jar 配置。
- spring 初始化的時候就會去ClassLoader找到所有的 META-INF/spring.handlers 文件。
- 加載文件中的 Handler,調用 init 進行初始化(這裏初始化就直接映射了命名空間與 element 之間的關係)。
- 真正解析的的時候拿到當前的 element 後,即可後去其命名空間,通過命名空間找到相應的 parser 對象進行解析。
7. 其他
debug 看代碼的時候,斷點DefaultNamespaceHandlerResolver#getHandlerMappings() 方法裏面的時候,handlerMappings 成員變量都是有值的。以爲有什麼黑魔法,百思不得解。最後發現另外以爲大神也遇到,附上鍊接:https://www.cnblogs.com/developer_chan/p/10002492.html