Spring中的自定義NamespaceHandler詳解
前言
通常情況下,Spring生態(tài)圈提供的功能已足夠使用,但不排除特殊情況下,需要匹配特殊及復(fù)雜的業(yè)務(wù)情況。Spring提供了可擴(kuò)展Schema支持,可以自定義命名空間進(jìn)行配置及解析。
自定義NamespaceHandler流程

自定義NamespaceHandler項(xiàng)目結(jié)構(gòu)

1) 設(shè)計(jì)自定義配置
設(shè)計(jì)配置包含id、name、sex、word、blob五個(gè)屬性,同步創(chuàng)建JavaBean,用于屬性載體。
package com.arhorchin.securitit.hello.bean;
/**
* @author Securitit.
* @note Introduce相關(guān)BEAN.
*/
public class HelloIntroduceBean {
/**
* id.
*/
private String id;
/**
* 姓名.
*/
private String name;
/**
* 性別.
*/
private String sex;
/**
* 語(yǔ)言.
*/
private String word;
/**
* 博客.
*/
private String blob;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getWord() {
return word;
}
public void setWord(String word) {
this.word = word;
}
public String getBlob() {
return blob;
}
public void setBlob(String blob) {
this.blob = blob;
}
}2) 定義XSD,描述自定義配置
XSD文件是對(duì)JavaBean的描述,需要注意xsd:schema節(jié)點(diǎn)的xmlns和targetNamespace屬性,需為要定義的命名空間。
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns="http://code.alibabatech.com/schema/hello"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:tool="http://www.springframework.org/schema/tool"
targetNamespace="http://code.alibabatech.com/schema/hello">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:import namespace="http://www.springframework.org/schema/beans" />
<xsd:import namespace="http://www.springframework.org/schema/tool" />
<xsd:complexType name="baseHelloType">
</xsd:complexType>
<xsd:complexType name="baseReferenceType">
</xsd:complexType>
<!-- 簡(jiǎn)介節(jié)點(diǎn)定義. -->
<xsd:element name="introduce">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="baseHelloType">
<xsd:attribute name="id" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
id.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="name" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
名稱.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="sex" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
性別.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="word" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
語(yǔ)言.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="blob" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
博客.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<!-- 代理對(duì)象設(shè)置. -->
<xsd:element name="reference">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="baseReferenceType">
<xsd:attribute name="id" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
see document
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="interface" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
see document
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
</xsd:schema>
3) 創(chuàng)建Handler
創(chuàng)建Handler,繼承NamespaceHandlerSupport,配置解析器
Handler的實(shí)現(xiàn)比較簡(jiǎn)單,主要目的是將自定義配置與解析器Parser進(jìn)行綁定,同時(shí)指定配置屬性載體JavaBean。
package com.arhorchin.securitit.hello.handler;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
import com.arhorchin.securitit.hello.bean.HelloIntroduceBean;
import com.arhorchin.securitit.hello.parser.IntroduceReqBeanDefinitionParser;
/**
* @author Securitit.
* @note Spring namespace定義.
*/
public class HelloNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("introduce", new IntroduceReqBeanDefinitionParser(HelloIntroduceBean.class, true));
}
}
4) 創(chuàng)建Parser
創(chuàng)建Parser,繼承BeanDefinitionParser,解析配置屬性。
Parser負(fù)責(zé)接收配置屬性值,對(duì)屬性值進(jìn)行校驗(yàn)處理,并初始化RootBeanDefinition,設(shè)置Bean相關(guān)屬性。
package com.arhorchin.securitit.hello.parser;
import org.apache.commons.lang3.StringUtils;
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;
/**
* @author Securitit.
* @note 解析Spring的XML文件, 設(shè)置Bean信息.
*/
public class IntroduceReqBeanDefinitionParser implements BeanDefinitionParser {
/**
* BEAN類型.
*/
private final Class<?> beanClass;
/**
* 是否必需.
*/
private final boolean required;
/**
* constructor.
* @param beanClass .
* @param required .
*/
public IntroduceReqBeanDefinitionParser(Class<?> beanClass, boolean required) {
this.beanClass = beanClass;
this.required = required;
}
protected Class<?> getBeanClass(Element element) {
return beanClass;
}
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
return parse(element, parserContext, beanClass, required);
}
/**
* Bean解析.
* @param element 當(dāng)前正在解析元素.
* @param parserContext 解析器上下文.
* @param beanClass 正在解析的Bean類.
* @param required 是否必需.
* @return 返回解析Bean定義.
*/
private static BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass,
boolean required) {
String id = null;
String name = null;
String sex = null;
String word = null;
String blob = null;
RootBeanDefinition beanDefinition = null;
// 取introduce元素屬性值.
id = element.getAttribute("id");
name = element.getAttribute("name");
sex = element.getAttribute("sex");
word = element.getAttribute("word");
blob = element.getAttribute("blob");
// 檢查id值域.
if (StringUtils.isEmpty(id)) {
throw new IllegalStateException("hello:introduce元素屬性id值必需.");
}
// 檢查name值域.
if (StringUtils.isEmpty(name)) {
throw new IllegalStateException("hello:introduce元素屬性name值必需.");
}
// 檢查sex值域.
if (StringUtils.isNotEmpty(sex) && !"male".equals(sex) && !"female".equals(sex)) {
throw new IllegalStateException("hello:introduce元素屬性sex值若存在,需為male或female.");
}
// 設(shè)置Bean定義.
beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClass(beanClass);
beanDefinition.setLazyInit(false);
parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
beanDefinition.getPropertyValues().addPropertyValue("id", id);
beanDefinition.getPropertyValues().addPropertyValue("name", name);
beanDefinition.getPropertyValues().addPropertyValue("sex", sex);
beanDefinition.getPropertyValues().addPropertyValue("word", word);
beanDefinition.getPropertyValues().addPropertyValue("blob", blob);
return beanDefinition;
}
}
5) 配置spring.handlers和spring.schemas文件
spring.handlers文件內(nèi)容:
http\://code.alibabatech.com/schema/hello=com.arhorchin.securitit.hello.handler.HelloNamespaceHandler
spring.schemas文件內(nèi)容:
http\://code.alibabatech.com/schema/hello/hello.xsd=META-INF/hello.xsd
6) 在Spring配置中進(jìn)行應(yīng)用
在應(yīng)用中增加配置,引入對(duì)應(yīng)的命名空間,并配置元素內(nèi)容。
<?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:hello="http://code.alibabatech.com/schema/hello"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/hello
http://code.alibabatech.com/schema/hello/hello.xsd">
<hello:introduce id="securitit" name="Securitit" sex="male" word="Java" blob="https://blog.csdn.net/securitit?spm=1001.2100.3001.5343"/>
</beans>
通過(guò)JUnit進(jìn)行測(cè)試加載配置文件,進(jìn)行測(cè)試。
package com.arhorchin.securitit.component;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.arhorchin.securitit.hello.bean.HelloIntroduceBean;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
locations = { "classpath:spring/applicationContext.xml" })
public class NamespaceHandlerTest {
/**
* logger.
*/
private Logger logger = LoggerFactory.getLogger(NamespaceHandlerTest.class);
@Autowired
private HelloIntroduceBean helloIntroduceBean;
@Test
public void test() {
logger.info("Spring NamespaceHandler 自定義測(cè)試.");
logger.info("hello:introduce元素屬性:[id=" + helloIntroduceBean.getId() + "], [name=" + helloIntroduceBean.getName()
+ "], [sex=" + helloIntroduceBean.getSex() + "], [word=" + helloIntroduceBean.getWord() + "], [blob="
+ helloIntroduceBean.getBlob() + "]");
}
}
可以看到,控制臺(tái)輸出了Spring配置文件中定義的內(nèi)容。
2021-01-28 16:38:58 INFO [com.arhorchin.securitit.component.NamespaceHandlerTest] Spring NamespaceHandler 自定義測(cè)試.
2021-01-28 16:38:58 INFO [com.arhorchin.securitit.component.NamespaceHandlerTest] hello:introduce元素屬性:[id=securitit], [name=Securitit], [sex=male], [word=Java], [blob=https://blog.csdn.net/securitit?spm=1001.2100.3001.5343]
總結(jié)
自定義NamespaceHandler的需求是會(huì)有很大幾率碰見(jiàn)的,當(dāng)然,在不知道的情況下,可能會(huì)選擇其他方案,這就需要多了解,以便在需要的時(shí)候做出正確的選擇。
源碼解析基于spring-framework-5.0.5.RELEASE版本源碼。
若文中存在錯(cuò)誤和不足,歡迎指正!
到此這篇關(guān)于Spring中的自定義NamespaceHandler詳解的文章就介紹到這了,更多相關(guān)自定義NamespaceHandler內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 通過(guò)Spring自定義NamespaceHandler實(shí)現(xiàn)命名空間解析(推薦)
- SpringBoot+Redis Bitmap實(shí)現(xiàn)活躍用戶統(tǒng)計(jì)
- Spring中的@CrossOrigin注解的使用詳細(xì)解讀
- SpringMVC注解@CrossOrigin跨域問(wèn)題詳解
- SpringBoot中的@CrossOrigin注解詳解
- springboot中的starter及自定義方法詳解
- SpringBoot使用JTA實(shí)現(xiàn)對(duì)多數(shù)據(jù)源的事務(wù)管理
- Spring核心容器之Bean創(chuàng)建過(guò)程詳解
相關(guān)文章
SpringBoot實(shí)現(xiàn)自定義Starter的步驟詳解
在SpringBoot中,Starter是一種特殊的依賴,它可以幫助我們快速地集成一些常用的功能,例如數(shù)據(jù)庫(kù)連接、消息隊(duì)列、Web框架等。在本文中,我們將介紹如何使用Spring Boot實(shí)現(xiàn)自定義Starter,需要的朋友可以參考下2023-06-06
2024版本IDEA創(chuàng)建Servlet模板的圖文教程
新版IDEA?2024.1.4中,用戶需要自行創(chuàng)建Servlet模板以解決Web項(xiàng)目無(wú)法通過(guò)右鍵創(chuàng)建Servlet的問(wèn)題,本文詳細(xì)介紹了添加ServletAnnotatedClass.java模板的步驟,幫助用戶快速配置并使用新的Servlet模板,需要的朋友可以參考下2024-10-10
Java實(shí)現(xiàn)輸出回環(huán)數(shù)(螺旋矩陣)的方法示例
這篇文章主要介紹了Java實(shí)現(xiàn)輸出回環(huán)數(shù)(螺旋矩陣)的方法,涉及java針對(duì)數(shù)組的遍歷、判斷、輸出等相關(guān)操作技巧,需要的朋友可以參考下2017-12-12
Spring實(shí)戰(zhàn)之調(diào)用實(shí)例工廠方法創(chuàng)建Bean操作示例
這篇文章主要介紹了Spring實(shí)戰(zhàn)之調(diào)用實(shí)例工廠方法創(chuàng)建Bean操作,結(jié)合實(shí)例形式分析了實(shí)例工廠方法創(chuàng)建Bean相關(guān)配置、實(shí)現(xiàn)方法及操作注意事項(xiàng),需要的朋友可以參考下2019-11-11
關(guān)于MyBatisSystemException異常產(chǎn)生的原因及解決過(guò)程
文章講述了在使用MyBatis進(jìn)行數(shù)據(jù)庫(kù)操作時(shí)遇到的異常及其解決過(guò)程,首先考慮了事務(wù)問(wèn)題,但未解決,接著懷疑是MyBatis的一級(jí)緩存問(wèn)題,關(guān)閉緩存后問(wèn)題依舊存在,最終發(fā)現(xiàn)是SQL映射文件中的參數(shù)傳遞錯(cuò)誤,使用了錯(cuò)誤的標(biāo)簽導(dǎo)致循環(huán)插入2025-01-01
MybatisPlus #{param}和${param}的用法詳解
這篇文章主要介紹了MybatisPlus #{param}和${param}的用法詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
解決springboot的aop切面不起作用問(wèn)題(失效的排查)
這篇文章主要介紹了解決springboot的aop切面不起作用問(wèn)題(失效的排查),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。 一起跟隨小編過(guò)來(lái)看看吧2020-04-04
Java中Stringbuilder和正則表達(dá)式示例詳解
Java語(yǔ)言為字符串連接運(yùn)算符(+)提供特殊支持,并為其他對(duì)象轉(zhuǎn)換為字符串,字符串連接是通過(guò)StringBuilder(或StringBuffer)類及其append方法實(shí)現(xiàn)的,這篇文章主要給大家介紹了關(guān)于Java中Stringbuilder和正則表達(dá)式的相關(guān)資料,需要的朋友可以參考下2024-02-02

