【spring原始碼學習】spring的IOC容器之自定義xml配置標籤擴充套件namspaceHandler向IOC容器中註冊bean
【spring以及第三方jar的案例】在spring中的aop相關配置的標籤,執行緒池相關配置的標籤,都是基於該種方式實現的。包括dubbo的配置標籤都是基於該方式實現的。
【一】原理
===>spring在解析xml標籤,一旦不是以<bean>開頭的元素,就會走org.springframework.beans.factory.xml.BeanDefinitionParserDelegate的parseCustomElement(Element ele)方法解析自定義的標籤
===>在該方法裡會根據xml中的名稱空間去查詢該標籤對應的NamespaceHandler介面的實現類去解析該配置標籤。該介面解析該配置標籤,並形成BeanDefinition註冊到IOC容器中。
===>該擴充套件需要做的內容:
(1)建立spring.handlers檔案,這是在解析xml配置檔案的時候,spring會透過xml檔案頭的名稱空間,去找該配置檔案中的NamespaceHandler的實現類。
(2)建立spring.schemas檔案,這是在xml檔案中配置自定義標籤的標籤合法驗證,也是合法檢驗。如果隨意填寫配置標籤,spring將無法解析。
(3)在所擴充套件的專案的resources目錄下,建立META-INF目錄,並將兩個檔案放置在目錄下。
(4)將spring.schemas中的xsd檔案配置在隨意的類路徑下。關於xsd檔案,可以瞭解:http://www.w3school.com.cn/schema/index.asp
(5)建立NamespaceHandler介面的實現類,建立BeanDefinitionParser的實現類。用於解析自已定義標籤的內容。
【二】實現例子:定義一個自定義標籤,實現一個類ZKClient的bean透過NamespaceHandler註冊IOC容器。本例子已經透過測試。不寫測試方法,只寫實現過程。
(1)spring.handlers檔案內容
http\://localhost.com/sxf=com.mobile.thinks.manages.namespaceHandler.SxfNameSpaceHandler
(2)spring.schemas檔案內容
http\://localhost.com/sxf.xsd=com/mobile/thinks/manages/namespaceHandler/sxf.xsd
(3)xsd檔案內容
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://localhost.com/sxf" xmlns="http://www.w3school.com.cn" elementFormDefault="qualified"> <xsd:element name="zk"> <xsd:complexType> <xsd:attribute name="host" use="required" > <xsd:simpleType> <xsd:restriction base="xsd:string"/> </xsd:simpleType> </xsd:attribute> <xsd:attribute name="port" use="required" > <xsd:simpleType> <xsd:restriction base="xsd:integer"/> </xsd:simpleType> </xsd:attribute> <xsd:attribute name="user" use="required" > <xsd:simpleType> <xsd:restriction base="xsd:string"/> </xsd:simpleType> </xsd:attribute> <xsd:attribute name="pwd" use="required" > <xsd:simpleType> <xsd:restriction base="xsd:string"/> </xsd:simpleType> </xsd:attribute> </xsd:complexType> </xsd:element> </xsd:schema>
(4)spring的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:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:task="http://www.springframework.org/schema/task" xmlns:sxf="http://localhost.com/sxf" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://localhost.com/sxf http://localhost.com/sxf.xsd "> <sxf:zk host="127.0.0.1" port="2181" user="shangxiaofei" pwd="smxcyx"/> <!-- <context:property-placeholder location="classpath:resources.properties"/> --> <!-- 掃描註解Bean --> <context:component-scan base-package="com.mobile.thinks.**"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/> <context:include-filter type="annotation" expression="org.springframework.beans.factory.annotation.Autowired"/> </context:component-scan> </beans>
(5)NamespaceHandler介面實現類的內容
package com.mobile.thinks.manages.namespaceHandler; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; /** * 自定義標籤的註解直譯器 * @author sxf * */ public class SxfNameSpaceHandler extends NamespaceHandlerSupport { /** * 初始化zk元素的具體解析器 */ @Override public void init() { registerBeanDefinitionParser("zk", new ZkBeanDefinitionParser()); } }
(6)BeanDefinitionParser介面實現類的內容
package com.mobile.thinks.manages.namespaceHandler; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.w3c.dom.Element; public class ZkBeanDefinitionParser implements BeanDefinitionParser{ private static final String HOST ="host"; private static final String PORT="port"; private static final String USER="user"; private static final String PWD="pwd"; /** * 解析標籤,形成特定的beanDefinition加入到ioc容器中 */ @Override public BeanDefinition parse(Element element, ParserContext parserContext) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ZkClient.class); String host=element.getAttribute("host"); String port=element.getAttribute("port"); String user=element.getAttribute("user"); String pwd=element.getAttribute("pwd"); builder.addPropertyValue("host",host); builder.addPropertyValue("port", Integer.valueOf(port)); builder.addPropertyValue("user", user); builder.addPropertyValue("pwd", pwd); parserContext.getRegistry().registerBeanDefinition("zkClient", builder.getBeanDefinition()); return builder.getBeanDefinition(); } }
(7)Zkclient類的內容,將來在專案中用一下方式直接使用該類
@Autowired
private ZkClient zkClient;
package com.mobile.thinks.manages.namespaceHandler; /** * 該類用自定義的NameSpaceHandler類解析配置檔案向IOC容器中註冊 * @author sxf * */ public class ZkClient { private String host; private int port; private String user; private String pwd; public String getHost() { return host; } public void setHost(String host) { this.host = host; } public int getPort() { return port; } public void setPort(int port) { this.port = port; } public String getUser() { return user; } public void setUser(String user) { this.user = user; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } }
【三】專案結構圖
【&&】需要注意的點,當maven打包的時候,預設不會將sxf.xsd檔案打包進jar包,將來專案用到的時候就不會從本地讀取到該sxf.xsd檔案,則需要在pom.xml檔案配置如下,才可以將檔案打包到相應的位置。也可以將其他格式的檔案,打包到jar包相應的位置,只需要修改相應檔案的字尾。
<build> <!-- 打成jar包的名字 --> <finalName>test</finalName> <!-- 這樣也可以把所有的readme檔案,打包到相應位置。其他的比如XX.xml檔案,也是同樣配置 --> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.txt</include> <include>**/*.xml</include> </includes> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xsd</include> </includes> </resource> </resources> </build>
該專案的jar完整的pom.xml檔案
<?xml version="1.0"?> <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.mobile</groupId> <artifactId>thinks</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <groupId>com.mobile</groupId> <artifactId>thinks-manages</artifactId> <version>1.0.0</version> <name>thinks-manages</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <build> <!-- <finalName>test</finalName> 打包成預設名字 --> <!-- 這樣也可以把所有的readme檔案,打包到相應位置。其他的比如XX.xml檔案,也是同樣配置 --> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.txt</include> <include>**/*.xml</include> <include>**/*.handlers</include> <include>**/*.schemas</include> <include>**/*.drl</include> </includes> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xsd</include> </includes> </resource> </resources> </build> <dependencies> <dependency> <groupId>com.mobile</groupId> <artifactId>thinks-service</artifactId> <version>${thinks.service.version}</version> </dependency> <dependency> <groupId>com.mobile</groupId> <artifactId>thinks-core</artifactId> <version>${thinks.core.version}</version> </dependency> <dependency> <groupId>com.mobile</groupId> <artifactId>thinks-commons</artifactId> <version>${thinks.commons.version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <!-- drools規則引擎 --> <dependency> <groupId>org.drools</groupId> <artifactId>drools-core</artifactId> </dependency> <dependency> <groupId>org.drools</groupId> <artifactId>drools-compiler</artifactId> </dependency> <dependency> <groupId>org.drools</groupId> <artifactId>knowledge-api</artifactId> </dependency> <dependency> <groupId>org.drools</groupId> <artifactId>drools-decisiontables</artifactId> </dependency> <dependency> <groupId>org.drools</groupId> <artifactId>drools-jsr94</artifactId> <version>${drools.version}</version><!--$NO-MVN-MAN-VER$--> </dependency> <!-- drools升級6.5.0.final版本依賴 --> <dependency> <groupId>org.eclipse.jdt.core.compiler</groupId> <artifactId>ecj</artifactId> </dependency> </dependencies> </project>
相關文章
- Spring IoC 容器的擴充套件2020-07-06Spring套件
- 如何向Spring IOC 容器 動態註冊bean2022-07-10SpringBean
- 深入理解Spring IOC容器及擴充套件2021-11-15Spring套件
- 【spring原始碼學習】spring的IOC容器之BeanFactoryPostProcessor介面學習2017-07-26Spring原始碼Bean
- 【spring原始碼學習】Spring的IOC容器之BeanPostProcessor介面學習2017-07-19Spring原始碼Bean
- spring原始碼解析之IOC容器(二)------載入和註冊2019-06-24Spring原始碼
- Spring(三):IoC容器裝配Bean(xml配置方式和註解方式)2016-07-05SpringBeanXML
- spring原始碼深度解析— IOC 之 自定義標籤解析2019-07-05Spring原始碼
- Spring IOC與Bean容器2017-09-19SpringBean
- spring-IOC容器原始碼分析(二)BeanDefinition註冊流程2018-11-19Spring原始碼Bean
- 【spring原始碼學習】spring的IOC容器在初始化bean過程2017-07-24Spring原始碼Bean
- spring原始碼解析之IOC容器(一)2019-06-23Spring原始碼
- 死磕Spring之IoC篇 - 解析自定義標籤(XML 檔案)2021-02-25SpringXML
- Spring IOC 一——Spring容器裝配Bean2019-05-10SpringBean
- 從原始碼看Spring中IOC容器的實現(二):IOC容器的初始化2019-04-28原始碼Spring
- Spring IOC容器-註解的方式2016-05-09Spring
- Spring學習筆記-IoC容器2015-10-09Spring筆記
- Spring的IOC容器2018-03-06Spring
- Spring原始碼閱讀-IoC容器解析2019-06-30Spring原始碼
- Spring IOC容器核心流程原始碼分析2021-08-16Spring原始碼
- Spring(十二):IOC容器中Bean的生命週期方法2018-05-24SpringBean
- spring-IOC容器原始碼分析(一)bean初始化流程2018-11-19Spring原始碼Bean
- 擴充spring元件之自定義標籤2019-04-14Spring元件
- spring原始碼解析之IOC容器(四)——屬性注入2019-07-01Spring原始碼
- spring原始碼解析之IOC容器(三)——依賴注入2019-06-26Spring原始碼依賴注入
- Spring原始碼分析:Spring IOC容器初始化2018-04-14Spring原始碼
- Spring框架IOC容器2019-03-03Spring框架
- Spring--IOC容器2021-03-28Spring
- Spring原始碼教程02--Spring的IoC容器分析2018-01-28Spring原始碼
- spring原始碼深度解析— IOC 之 容器的基本實現2019-07-02Spring原始碼
- Spring Ioc原始碼分析系列--容器例項化Bean的四種方法2022-06-06Spring原始碼Bean
- 《spring原始碼解讀》 - IoC 之解析 import 標籤2020-09-02Spring原始碼Import
- Spring Ioc原始碼分析系列--Ioc容器註冊BeanPostProcessor後置處理器以及事件訊息處理2022-05-18Spring原始碼Bean事件
- (001)Spring 之 IOC及其容器2017-12-13Spring
- Spring5原始碼解析_IOC之容器的基本實現2022-01-05Spring原始碼
- Spring IOC XML配置2021-11-28SpringXML
- spring原始碼深度解析— IOC 之 bean 建立2019-07-08Spring原始碼Bean
- Spring原始碼之容器的功能擴充套件和refresh方法解析2022-06-17Spring原始碼套件