激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語(yǔ)言|JavaScript|易語(yǔ)言|vb.net|

服務(wù)器之家 - 編程語(yǔ)言 - Java教程 - Spring源碼解密之自定義標(biāo)簽與解析

Spring源碼解密之自定義標(biāo)簽與解析

2021-03-19 13:19唐亞峰 Java教程

這篇文章主要給大家介紹了關(guān)于Spring源碼解密之自定義標(biāo)簽與解析的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參借鑒,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。

前言

在 上一節(jié) spring解密 - 默認(rèn)標(biāo)簽的解析 中,重點(diǎn)分析了 spring 對(duì)默認(rèn)標(biāo)簽是如何解析的,那么本章繼續(xù)講解標(biāo)簽解析,著重講述如何對(duì)自定義標(biāo)簽進(jìn)行解析。話不多說(shuō)了,來(lái)一起看看詳細(xì)的介紹吧。

自定義標(biāo)簽

在講解 自定義標(biāo)簽解析 之前,先看下如何自定義標(biāo)簽

定義 xsd 文件

定義一個(gè) xsd 文件描述組件內(nèi)容

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns="http://www.battcn.com/schema/battcn" xmlns:xsd="http://www.w3.org/2001/xmlschema" xmlns:beans="http://www.springframework.org/schema/beans" targetnamespace="http://www.battcn.com/schema/battcn"
 elementformdefault="qualified"
 attributeformdefault="unqualified">
 <xsd:import namespace="http://www.springframework.org/schema/beans" />
 <xsd:element name="application">
 <xsd:complextype>
 <xsd:complexcontent>
 <xsd:extension base="beans:identifiedtype">
  <xsd:attribute name="name" type="xsd:string" use="required"/>
 </xsd:extension>
 </xsd:complexcontent>
 </xsd:complextype>
 </xsd:element>
</xsd:schema>
  • 聲明命名空間: 值得注意的是 xmlns 與 targetnamespace 可以是不存在,只要映射到指定 xsd 就行了。
  • 定義復(fù)合元素: 這里的 application 就是元素的名稱,使用時(shí) <battcn:application id="battcn"/>
  • 定義元素屬性: 元素屬性就是 attribute 標(biāo)簽,我們聲明了一個(gè)必填的 name 的屬性,使用時(shí) <battcn:application id="battcn" name="levin"/>

定義解析規(guī)則

1.創(chuàng)建一個(gè)類實(shí)現(xiàn) beandefinitionparser 接口(也可繼承 spring 提供的類),用來(lái)解析 xsd 文件中的定義和組件定義

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public class applicationbeandefinitionparser extends abstractsinglebeandefinitionparser {
 @override
 protected class getbeanclass(element element) {
 // 接收對(duì)象的類型 如:string name = (string) context.getbean("battcn");
 return string.class;
 }
 @override
 protected void doparse(element element, beandefinitionbuilder bean) {
 // 在 xsd 中定義的 name 屬性
 string name = element.getattribute("name");
 bean.addconstructorargvalue(name);
 }
}

這里創(chuàng)建了一個(gè) applicationbeandefinitionparser 繼承 abstractsinglebeandefinitionparser(是:beandefinitionparser 的子類), 重點(diǎn)就是重寫的 doparse,在這個(gè)里面解析 xml 標(biāo)簽的,然后將解析出的 value(levin) 通過(guò)構(gòu)造器方式注入進(jìn)去

2.創(chuàng)建一個(gè)類繼承 namespacehandlersupport 抽象類

?
1
2
3
4
5
6
public class battcnnamespacehandler extends namespacehandlersupport {
 @override
 public void init() {
 registerbeandefinitionparser("application", new applicationbeandefinitionparser());
 }
}

battcnnamespacehandler 的作用特別簡(jiǎn)單,就是告訴 spring 容器,標(biāo)簽 <battcn:application /> 應(yīng)該由那個(gè)解析器解析(這里是我們自定義的:applicationbeandefinitionparser),負(fù)責(zé)將組件注冊(cè)到 spring 容器

3.編寫 spring.handlers 和 spring.schemas 文件

文件存放的目錄位于 resources/meta-inf/文件名

spring.handlers

?
1
http\://www.battcn.com/schema/battcn=com.battcn.handler.battcnnamespacehandler

spring.schemas

?
1
http\://www.battcn.com/schema/battcn.xsd=battcn.xsd

4.使用自定義標(biāo)簽

申明 bean.xml 文件,定義如下

?
1
2
3
4
5
6
7
<?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:battcn="http://www.battcn.com/schema/battcn" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
 http://www.battcn.com/schema/battcn
 http://www.battcn.com/schema/battcn.xsd">
 <battcn:application id="battcn" name="levin"/>
</beans>

創(chuàng)建一個(gè)測(cè)試類,如果看到控制臺(tái)輸出了 levin 字眼,說(shuō)明自定義標(biāo)簽一切正常

?
1
2
3
4
5
6
7
public class application {
 public static void main(string[] args) {
 applicationcontext context = new classpathxmlapplicationcontext("bean.xml");
 string name = (string) context.getbean("battcn");
 system.out.println(name);
 }
}

5.如圖所示

Spring源碼解密之自定義標(biāo)簽與解析

源碼分析

自定義標(biāo)簽解析入口

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class beandefinitionparserdelegate {
 @nullable
 public beandefinition parsecustomelement(element ele, @nullable beandefinition containingbd) {
 // 獲取命名空間地址 http://www.battcn.com/schema/battcn
 string namespaceuri = getnamespaceuri(ele);
 if (namespaceuri == null) {
 return null;
 }
 // namespacehandler 就是 自定義的 battcnnamespacehandler 中注冊(cè)的 application
 namespacehandler handler = this.readercontext.getnamespacehandlerresolver().resolve(namespaceuri);
 if (handler == null) {
 error("unable to locate spring namespacehandler for xml schema namespace [" + namespaceuri + "]", ele);
 return null;
 }
 return handler.parse(ele, new parsercontext(this.readercontext, this, containingbd));
 }
}

與默認(rèn)標(biāo)簽解析規(guī)則一樣的是,都是通過(guò) getnamespaceuri(node node) 來(lái)獲取命名空間,那么 this.readercontext.getnamespacehandlerresolver() 是從哪里獲取的呢?我們跟蹤下代碼,可以發(fā)現(xiàn)在項(xiàng)目啟動(dòng)的時(shí)候,會(huì)在 xmlbeandefinitionreader 將所有的 meta-inf/spring.handles 文件內(nèi)容解析,存儲(chǔ)在 handlermappers(一個(gè)concurrenthashmap) 中,在調(diào)用 resolve(namespaceuri) 校驗(yàn)的時(shí)候在將緩存的內(nèi)容提取出來(lái)做對(duì)比

?
1
2
3
4
5
6
7
8
public class xmlbeandefinitionreader {
 public namespacehandlerresolver getnamespacehandlerresolver() {
 if (this.namespacehandlerresolver == null) {
 this.namespacehandlerresolver = createdefaultnamespacehandlerresolver();
 }
 return this.namespacehandlerresolver;
 }
}

resolve

1.加載指定的 namespacehandler 映射,并且提取的 namespacehandler 緩存起來(lái),然后返回

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class defaultnamespacehandlerresolver {
 @override
 @nullable
 public namespacehandler resolve(string namespaceuri) {
 map<string, object> handlermappings = gethandlermappings();
 // 從 handlermappings 提取 handlerorclassname
 object handlerorclassname = handlermappings.get(namespaceuri);
 if (handlerorclassname == null) {
 return null;
 }
 else if (handlerorclassname instanceof namespacehandler) {
 return (namespacehandler) handlerorclassname;
 }
 else {
 string classname = (string) handlerorclassname;
 try {
 class<?> handlerclass = classutils.forname(classname, this.classloader);
 if (!namespacehandler.class.isassignablefrom(handlerclass)) {
 throw new fatalbeanexception("class [" + classname + "] for namespace [" + namespaceuri +
 "] does not implement the [" + namespacehandler.class.getname() + "] interface");
 }
 // 根據(jù)命名空間尋找對(duì)應(yīng)的信息
 namespacehandler namespacehandler = (namespacehandler) beanutils.instantiateclass(handlerclass);
 // handler 初始化
 namespacehandler.init();
 handlermappings.put(namespaceuri, namespacehandler);
 return namespacehandler;
 }
 catch (classnotfoundexception ex) {
 throw new fatalbeanexception("namespacehandler class [" + classname + "] for namespace [" +
 namespaceuri + "] not found", ex);
 }
 catch (linkageerror err) {
 throw new fatalbeanexception("invalid namespacehandler class [" + classname + "] for namespace [" +
 namespaceuri + "]: problem with handler class file or dependent class", err);
 }
 }
 }
}

標(biāo)簽解析

加載完 namespacehandler 之后,battcnnamespacehandler 就已經(jīng)被初始化為 了,而 battcnnamespacehandler 也調(diào)用了 init() 方法完成了初始化的工作。因此就接著執(zhí)行這句代碼: handler.parse(ele, new parsercontext(this.readercontext, this, containingbd)); 具體標(biāo)簽解。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class namespacehandlersupport {
 @override
 @nullable
 public beandefinition parse(element element, parsercontext parsercontext) {
 beandefinitionparser parser = findparserforelement(element, parsercontext);
 return (parser != null ? parser.parse(element, parsercontext) : null);
 }
 @nullable
 private beandefinitionparser findparserforelement(element element, parsercontext parsercontext) {
 // 解析出 <battcn:application /> 中的 application
 string localname = parsercontext.getdelegate().getlocalname(element);
 beandefinitionparser parser = this.parsers.get(localname);
 if (parser == null) {
 parsercontext.getreadercontext().fatal(
 "cannot locate beandefinitionparser for element [" + localname + "]", element);
 }
 return parser;
 }
}

簡(jiǎn)單來(lái)說(shuō)就是從 parsers 中尋找到 applicationbeandefinitionparser 實(shí)例,并調(diào)用其自身的 doparse 方法進(jìn)行進(jìn)一步解析。最后就跟解析默認(rèn)標(biāo)簽的套路一樣了…

總結(jié)

熬過(guò)幾個(gè)無(wú)人知曉的秋冬春夏,撐過(guò)去一切都會(huì)順著你想要的方向走…

好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)服務(wù)器之家的支持。

說(shuō)點(diǎn)什么

全文代碼:https://gitee.com/battcn/battcn-spring-source/tree/master/chapter2

原文鏈接:http://blog.battcn.com/2018/01/12/spring/spring-3/

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 成人视屏在线 | 国产精品一区在线观看 | 国产女厕一区二区三区在线视 | 中文字幕22页 | 黄色av片三级三级三级免费看 | 日韩av在线资源 | 国产精品视频二区不卡 | 国产一级免费在线视频 | 国产免费黄色 | 高清国产午夜精品久久久久久 | 免费a级黄色毛片 | 91精品国产综合久久久欧美 | 日韩av片在线免费观看 | 亚洲成人在线视频网 | 羞羞的视频在线 | 92看片淫黄大片一级 | 日韩激情 | 一边吃奶一边摸下娇喘 | 国产一区成人 | 狠狠一区二区 | 黄在线 | 成人免费毛片一 | 欧美日韩国产一区二区三区在线观看 | 法国性xxx精品hd专区 | 成人性生活视频在线观看 | 国产欧美日韩二区 | www国产成人免费观看视频 | 国产精品国产三级国产aⅴ无密码 | 成人在线观看一区二区 | 黄视频在线网站 | 耽美男男肉文 | 美女黄页网站免费进入 | 99激情| 国产亚洲精品精 | 久久亚洲春色中文字幕久久 | 欧美色性| 91久久夜色精品国产网站 | 在线天堂资源 | 精品久久久久久综合日本 | www.91操 | 在线a |