国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Spring源碼解密之默認標簽的解析

Spring源碼解密之默認標簽的解析

2021-03-19 12:21唐亞峰 Java教程

這篇文章主要給大家介紹了關于Spring源碼解密之默認標簽的解析的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。

前言

緊跟上篇 spring解密 - xml解析 與 bean注冊 ,我們接著往下分析源碼,話不多說了,來一起看看詳細的介紹吧。

解密

在 spring 的 xml 配置里面有兩大類聲明,一個是默認的如 <bean id="person" class="com.battcn.bean.person"/> ,另一類就是自定義的如<tx:annotation-driven /> ,兩種標簽的解析方式差異是非常大的。parsebeandefinitions 方法就是用來區分不同標簽所使用的解析方式。通過 node.getnamespaceuri() 方法獲取命名空間,判斷是默認命名空間還是自定義命名空間,并與 spring 中固定的命名空間 http://www.springframework.org/schema/beans 進行比對,如果一致則采用parsedefaultelement(ele, delegate);否則就是delegate.parsecustomelement(ele);

默認標簽的解析

parsedefaultelement 對 4 種不同的標簽 import、alias、bean、beans 做了不同的處理,其中 bean 標簽的解析最為復雜也最為重要,所以我們將從 bean 開始深入分析,如果能理解此標簽的解析過程,其他標簽的解析自然會迎刃而解。上一篇中只是簡單描述了一下,本篇我們圍繞解析模塊詳細的探討一下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class defaultbeandefinitiondocumentreader implements beandefinitiondocumentreader {
 private void parsedefaultelement(element ele, beandefinitionparserdelegate delegate) {
 // import 標簽解析
 if (delegate.nodenameequals(ele, import_element)) {
 importbeandefinitionresource(ele);
 }
 // alias 標簽解析
 else if (delegate.nodenameequals(ele, alias_element)) {
 processaliasregistration(ele);
 }
 // bean 標簽解析
 else if (delegate.nodenameequals(ele, bean_element)) {
 processbeandefinition(ele, delegate);
 }
 // import 標簽解析
 else if (delegate.nodenameequals(ele, nested_beans_element)) {
 // beans標簽解析 遞歸方式
 doregisterbeandefinitions(ele);
 }
 }
}

Spring源碼解密之默認標簽的解析

首先我們來分析下當類中的 processbeandefinition(ele, delegate)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
protected void processbeandefinition(element ele, beandefinitionparserdelegate delegate) {
 // 委托beandefinitiondelegate類的parsebeandefinitionelement方法進行元素解析
 beandefinitionholder bdholder = delegate.parsebeandefinitionelement(ele);
 if (bdholder != null) {
 // 當返回的bdholder不為空的情況下若存在默認標簽的子節點下再有自定義屬性,還需要再次對自定義標簽進行解析
 bdholder = delegate.decoratebeandefinitionifrequired(ele, bdholder);
 try {
 // 解析完成后需要對解析后的bdholder進行注冊,注冊操作委托給了beandefinitionreaderutils的registerbeandefinition方法
 beandefinitionreaderutils.registerbeandefinition(bdholder, getreadercontext().getregistry());
 }
 catch (beandefinitionstoreexception ex) {
 getreadercontext().error("failed to register bean definition with name '" +
 bdholder.getbeanname() + "'", ele, ex);
 }
 // 最后發出響應事件,通知相關監聽器這個bean已經被加載
 getreadercontext().firecomponentregistered(new beancomponentdefinition(bdholder));
 }
}

這段代碼中:

  • 首先委托 beandefinitionparsedelegate 對節點做了解析,并返回了一個 beandefinitionholder 的實例,在這個實例中已經包含了配置文件中配置的各種屬性了
  • 如果在當前子節點中存在自定義屬性,則還需要對自定義標簽進行解析
  • 解析完成后,需要對解析后的 bdholder 進行注冊,同樣注冊操作委托給了 beandefinitionreaderutils
  • 最后發出響應事件,通知相關監聽器這個 bean 已經被加載

下面我們詳細分析下,spring 是如何解析各個標簽和節點的

bean 標簽解析

?
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
public class beandefinitionparserdelegate {
 @nullable
 public beandefinitionholder parsebeandefinitionelement(element ele, @nullable beandefinition containingbean) {
 // 獲取bean標簽的id屬性
 string id = ele.getattribute(id_attribute);
 // 獲取bean標簽的name屬性
 string nameattr = ele.getattribute(name_attribute);
 list<string> aliases = new arraylist<>();
 if (stringutils.haslength(nameattr)) {
 // 將name屬性的值通過,; 進行分割 轉為字符串數字(即在配置文件中如配置多個name 在此做處理)
 string[] namearr = stringutils.tokenizetostringarray(nameattr, multi_value_attribute_delimiters);
 aliases.addall(arrays.aslist(namearr));
 }
 string beanname = id;
 // 如果id為空 使用配置的第一個name屬性作為id
 if (!stringutils.hastext(beanname) && !aliases.isempty()) {
 beanname = aliases.remove(0);
 if (logger.isdebugenabled()) {
 logger.debug("no xml 'id' specified - using '" + beanname + "' as bean name and " + aliases + " as aliases");
 }
 }
 if (containingbean == null) {
 // 校驗beanname和aliases的唯一性
 // 內部核心為使用usednames集合保存所有已經使用了的beanname和alisa
 checknameuniqueness(beanname, aliases, ele);
 }
 // 進一步解析其他所有屬性到genericbeandefinition對象中
 abstractbeandefinition beandefinition = parsebeandefinitionelement(ele, beanname, containingbean);
 if (beandefinition != null) {
 // 如果bean沒有指定beanname 那么使用默認規則為此bean生成beanname
 if (!stringutils.hastext(beanname)) {
 try {
 if (containingbean != null) {
 beanname = beandefinitionreaderutils.generatebeanname(beandefinition, this.readercontext.getregistry(), true);
 } else {
 beanname = this.readercontext.generatebeanname(beandefinition);
 // register an alias for the plain bean class name, if still possible,
 // if the generator returned the class name plus a suffix.
 // this is expected for spring 1.2/2.0 backwards compatibility.
 string beanclassname = beandefinition.getbeanclassname();
 if (beanclassname != null &&
 beanname.startswith(beanclassname) && beanname.length() > beanclassname.length() &&
 !this.readercontext.getregistry().isbeannameinuse(beanclassname)) {
 aliases.add(beanclassname);
 }
 }
 if (logger.isdebugenabled()) {
 logger.debug("neither xml 'id' nor 'name' specified - " + "using generated bean name [" + beanname + "]");
 }
 } catch (exception ex) {
 error(ex.getmessage(), ele);
 return null;
 }
 }
 string[] aliasesarray = stringutils.tostringarray(aliases);
 // 將信息封裝到beandefinitionholder對象中
 return new beandefinitionholder(beandefinition, beanname, aliasesarray);
 }
 return null;
 }
}

該方法主要處理了 id、name、alias 等相關屬性,生成了 beanname,并且在重載函數 parsebeandefinitionelement(ele, beanname, containingbean)方法中完成核心的標簽解析。

接下來重點分析parsebeandefinitionelement(element ele, string beanname, @nullable beandefinition containingbean)

看下它是如何完成標簽解析操作的

bean 節點與屬性解析

?
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
40
41
42
43
44
45
46
47
48
49
50
51
52
@nullable
public abstractbeandefinition parsebeandefinitionelement(
 element ele, string beanname, @nullable beandefinition containingbean) {
 this.parsestate.push(new beanentry(beanname));
 // 獲取bean標簽的class屬性
 string classname = null;
 if (ele.hasattribute(class_attribute)) {
 classname = ele.getattribute(class_attribute).trim();
 }
 // 獲取bean標簽的parent屬性
 string parent = null;
 if (ele.hasattribute(parent_attribute)) {
 parent = ele.getattribute(parent_attribute);
 }
 try {
 // 創建用于承載屬性的abstractbeandefinition
 abstractbeandefinition bd = createbeandefinition(classname, parent);
 // 獲取bean標簽各種屬性
 parsebeandefinitionattributes(ele, beanname, containingbean, bd);
 // 解析description標簽
 bd.setdescription(domutils.getchildelementvaluebytagname(ele, description_element));
 // 解析meta標簽
 parsemetaelements(ele, bd);
 // 解析lookup-method標簽
 parselookupoverridesubelements(ele, bd.getmethodoverrides());
 // 解析replaced-method標簽
 parsereplacedmethodsubelements(ele, bd.getmethodoverrides());
 // 解析constructor-arg標簽
 parseconstructorargelements(ele, bd);
 // 解析property標簽
 parsepropertyelements(ele, bd);
 // 解析qualifier標簽
 parsequalifierelements(ele, bd);
 bd.setresource(this.readercontext.getresource());
 bd.setsource(extractsource(ele));
 
 return bd;
 }
 catch (classnotfoundexception ex) {
 error("bean class [" + classname + "] not found", ele, ex);
 }
 catch (noclassdeffounderror err) {
 error("class that bean class [" + classname + "] depends on not found", ele, err);
 }
 catch (throwable ex) {
 error("unexpected failure during bean definition parsing", ele, ex);
 }
 finally {
 this.parsestate.pop();
 }
 return null;
}

進一步解析其他屬性和元素(元素和屬性很多,所以這是一個龐大的工作量)并統一封裝至 genericbeandefinition 中, 解析完成這些屬性和元素之后,如果檢測到 bean 沒有指定的 beanname,那么便使用默認的規則為 bean 生成一個 beanname。

Spring源碼解密之默認標簽的解析

?
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
// beandefinitionparserdelegate.java
protected abstractbeandefinition createbeandefinition(@nullable string classname, @nullable string parentname)
 throws classnotfoundexception {
 return beandefinitionreaderutils.createbeandefinition(
 parentname, classname, this.readercontext.getbeanclassloader());
}
public class beandefinitionreaderutils {
 public static abstractbeandefinition createbeandefinition(
 @nullable string parentname, @nullable string classname, @nullable classloader classloader) throws classnotfoundexception {
 genericbeandefinition bd = new genericbeandefinition();
 // parentname可能為空
 bd.setparentname(parentname);
 // 如果classloader不為空
 // 則使用傳入的classloader同一虛擬機加載類對象 否則只記錄classloader
 if (classname != null) {
 if (classloader != null) {
 bd.setbeanclass(classutils.forname(classname, classloader));
 }
 else {
 bd.setbeanclassname(classname);
 }
 }
 return bd;
 }
}

beandefinition 是 <bean> 在容器中的內部表示形式,beandefinition 和 <bean> 是一一對應的。同時 beandefinition 會被注冊到 beandefinitionregistry 中,beandefinitionregistry 就像 spring 配置信息的內存數據庫。

至此 createbeandefinition(classname, parent); 已經說完了,而且我們也獲得了 用于承載屬性的abstractbeandefinition,接下來看看 parsebeandefinitionattributes(ele, beanname, containingbean, bd); 是如何解析 bean 中的各種標簽屬性的

?
1
2
3
4
5
6
7
8
public class beandefinitionparserdelegate {
 public abstractbeandefinition parsebeandefinitionattributes(element ele, string beanname,
 @nullable beandefinition containingbean, abstractbeandefinition bd) {
 // ...省略詳細代碼,該部分代碼主要就是通過 if else 判斷是否含有指定的屬性,如果有就 bd.set(attribute);
 return bd;
 }
}
```

`bean` 標簽的完整解析到這就已經全部結束了,其中 `bean` 標簽下的元素解析都大同小異,有興趣的可以自己跟蹤一下源代碼看看 `qualifier、lookup-method` 等解析方式(*相對 `bean` 而言不復雜*)。自定義標簽內容較多會在下一章詳細介紹。

最后將獲取到的信息封裝到 `beandefinitionholder` 實例中

?
1
2
3
4
5
6
7
``` java
// beandefinitionparserdelegate.java
@nullable
public beandefinitionholder parsebeandefinitionelement(element ele, @nullable beandefinition containingbean) {
 // ...
 return new beandefinitionholder(beandefinition, beanname, aliasesarray);
}

注冊解析的 beandefinition

在解析完配置文件后我們已經獲取了 bean 的所有屬性,接下來就是對 bean 的注冊了

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class beandefinitionreaderutils {
 public static void registerbeandefinition(
 beandefinitionholder definitionholder, beandefinitionregistry registry)
 throws beandefinitionstoreexception {
 // 使用 beanname 做唯一標識符
 string beanname = definitionholder.getbeanname();
 // 注冊bean的核心代碼
 registry.registerbeandefinition(beanname, definitionholder.getbeandefinition());
 // 為bean注冊所有的別名
 string[] aliases = definitionholder.getaliases();
 if (aliases != null) {
 for (string alias : aliases) {
 registry.registeralias(beanname, alias);
 }
 }
 }
}

以上代碼主要完成兩個功能,一是使用 beanname 注冊 beandefinition,二是完成了對別名的注冊

Spring源碼解密之默認標簽的解析

beanname 注冊 beandefinition

?
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
public class defaultlistablebeanfactory {
 @override
 public void registerbeandefinition(string beanname, beandefinition beandefinition)
 throws beandefinitionstoreexception {
 assert.hastext(beanname, "bean name must not be empty");
 assert.notnull(beandefinition, "beandefinition must not be null");
 if (beandefinition instanceof abstractbeandefinition) {
 try {
 // 注冊前的最后一次校驗,這里的校驗不同于xml文件校驗
 // 主要是對于abstractbeandefinition屬性中的methodoverrides校驗
 // 校驗methodoverrides是否與工廠方法并存或者methodoverrides對于的方法根本不存在
 ((abstractbeandefinition) beandefinition).validate();
 }
 catch (beandefinitionvalidationexception ex) {
 throw new beandefinitionstoreexception(beandefinition.getresourcedescription(), beanname,
 "validation of bean definition failed", ex);
 }
 }
 beandefinition oldbeandefinition;
 // 獲取緩存中的 beandefinition
 oldbeandefinition = this.beandefinitionmap.get(beanname);
 if (oldbeandefinition != null) {
 // 如果緩存中存在 判斷是否允許覆蓋
 if (!isallowbeandefinitionoverriding()) {
 throw new beandefinitionstoreexception(beandefinition.getresourcedescription(), beanname,
 "cannot register bean definition [" + beandefinition + "] for bean '" + beanname +
 "': there is already [" + oldbeandefinition + "] bound.");
 }
 else if (oldbeandefinition.getrole() < beandefinition.getrole()) {
 // e.g. was role_application, now overriding with role_support or role_infrastructure
 if (this.logger.iswarnenabled()) {
 this.logger.warn("overriding user-defined bean definition for bean '" + beanname +
 "' with a framework-generated bean definition: replacing [" +
 oldbeandefinition + "] with [" + beandefinition + "]");
 }
 }
 else if (!beandefinition.equals(oldbeandefinition)) {
 if (this.logger.isinfoenabled()) {
 this.logger.info("overriding bean definition for bean '" + beanname +
 "' with a different definition: replacing [" + oldbeandefinition +
 "] with [" + beandefinition + "]");
 }
 }
 else {
 if (this.logger.isdebugenabled()) {
 this.logger.debug("overriding bean definition for bean '" + beanname +
 "' with an equivalent definition: replacing [" + oldbeandefinition +
 "] with [" + beandefinition + "]");
 }
 }
 // 如果允許覆蓋,保存beandefinition到beandefinitionmap中
 this.beandefinitionmap.put(beanname, beandefinition);
 }
 else {
 // 判斷是否已經開始創建bean
 if (hasbeancreationstarted()) {
 // cannot modify startup-time collection elements anymore (for stable iteration)
 synchronized (this.beandefinitionmap) {
 // 保存beandefinition到beandefinitionmap中
 this.beandefinitionmap.put(beanname, beandefinition);
 // 更新已經注冊的beanname
 list<string> updateddefinitions = new arraylist<>(this.beandefinitionnames.size() + 1);
 updateddefinitions.addall(this.beandefinitionnames);
 updateddefinitions.add(beanname);
 this.beandefinitionnames = updateddefinitions;
 if (this.manualsingletonnames.contains(beanname)) {
 set<string> updatedsingletons = new linkedhashset<>(this.manualsingletonnames);
 updatedsingletons.remove(beanname);
 this.manualsingletonnames = updatedsingletons;
 }
 }
 }
 else {
 // 還沒開始創建bean
 this.beandefinitionmap.put(beanname, beandefinition);
 this.beandefinitionnames.add(beanname);
 this.manualsingletonnames.remove(beanname);
 }
 this.frozenbeandefinitionnames = null;
 }
 if (oldbeandefinition != null || containssingleton(beanname)) {
 // 重置beanname對應的緩存
 resetbeandefinition(beanname);
 }
 }
}
  • 對 abstractbeandefinition 的校驗,主要是針對 abstractbeandefinition 的 methodoverrides 屬性的
  • 對 beanname 已經注冊的情況的處理,如果設置了不允許 bean 的覆蓋,則需要拋出異常,否則直接覆蓋
  • 使用 beanname 作為 key,beandefinition 為 value 加入 beandefinitionmap 存儲
  • 如果緩存中已經存在,并且該 bean 為單例模式則清楚 beanname 對應的緩存

注冊別名

注冊好了 beandefinition,接下來就是注冊 alias。注冊的 alias 和 beanname 的對應關系存放在了 aliasmap 中,沿著類的繼承鏈會發現 registeralias 的方法是在 simplealiasregistry 中實現的

?
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
public class simplealiasregistry {
 /** map from alias to canonical name */
 private final map<string, string> aliasmap = new concurrenthashmap<>(16);
 public void registeralias(string name, string alias) {
 assert.hastext(name, "'name' must not be empty");
 assert.hastext(alias, "'alias' must not be empty");
 if (alias.equals(name)) {
  // 如果beanname與alias相同的話不記錄alias 并刪除對應的alias
  this.aliasmap.remove(alias);
 } else {
  string registeredname = this.aliasmap.get(alias);
  if (registeredname != null) {
  if (registeredname.equals(name)) {
   // 如果別名已經注冊過并且指向的name和當前name相同 不做任何處理
   return;
  }
  // 如果alias不允許被覆蓋則拋出異常
  if (!allowaliasoverriding()) {
   throw new illegalstateexception("cannot register alias '" + alias + "' for name '" + name + "': it is already registered for name '" + registeredname + "'.");
  }
  }
  // 校驗循環指向依賴 如a->b b->c c->a則出錯
  checkforaliascircle(name, alias);
  this.aliasmap.put(alias, name);
 }
 }
}

通過 checkforaliascircle() 方法來檢查 alias 循環依賴,當 a -> b 存在時,若再次出現 a -> c -> b 則會拋出異常:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
protected void checkforaliascircle(string name, string alias) {
 if (hasalias(alias, name)) {
 throw new illegalstateexception("cannot register alias '" + alias +
 "' for name '" + name + "': circular reference - '" +
 name + "' is a direct or indirect alias for '" + alias + "' already");
 }
}
public boolean hasalias(string name, string alias) {
 for (map.entry<string, string> entry : this.aliasmap.entryset()) {
 string registeredname = entry.getvalue();
 if (registeredname.equals(name)) {
 string registeredalias = entry.getkey();
 return (registeredalias.equals(alias) || hasalias(registeredalias, alias));
 }
 }
 return false;
}

至此,注冊別名也完成了,主要完成了以下幾個工作

  • 如果 beanname 與 alias 相同的話不記錄 alias 并刪除對應的 alias
  • 如果別名已經注冊過并且指向的name和當前name相同 不做任何處理
  • 如果別名已經注冊過并且指向的name和當前name不相同 判斷是否允許被覆蓋
  • 校驗循環指向依賴 如a->b b->c c->a則出錯

發送通知

通知監聽器解析及注冊完成

?
1
2
3
4
5
//defaultbeandefinitiondocumentreader.java
protected void processbeandefinition(element ele, beandefinitionparserdelegate delegate) {
 // send registration event.
 getreadercontext().firecomponentregistered(new beancomponentdefinition(bdholder));
}

通過 firecomponentregistered 方法進行通知監聽器解析及注冊完成工作,這里的實現只為擴展,當程序開發人員需要對注冊 beandefinition事件進行監聽時,可以通過注冊監聽器的方式并將處理邏輯寫入監聽器中,目前 spring 中并沒有對此事件做任何處理

其中 readercontext 是在類 xmlbeandefinitionreader 中調用 createreadercontext 生成的,然后調用 firecomponentregistered()

alias 標簽解析

spring 提供了 <alias name="person" alias="p"/> 方式來進行別名的配置,該標簽解析是在 processaliasregistration(element ele) 方法中完成的

?
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
public class defaultbeandefinitiondocumentreader {
 protected void processaliasregistration(element ele) {
 // 獲取 alisa 標簽 name 屬性
 string name = ele.getattribute(name_attribute);
 // 獲取 alisa 標簽 alias 屬性
 string alias = ele.getattribute(alias_attribute);
 boolean valid = true;
 if (!stringutils.hastext(name)) {
  getreadercontext().error("name must not be empty", ele);
  valid = false;
 } if (!stringutils.hastext(alias)) {
  getreadercontext().error("alias must not be empty", ele);
  valid = false;
 }
 if (valid) {
  try {
  // 進行別名注冊
  getreadercontext().getregistry().registeralias(name, alias);
  } catch (exception ex) {
  getreadercontext().error("failed to register alias '" + alias +
   "' for bean with name '" + name + "'", ele, ex);
  }
  // 別名注冊后告知監聽器做相應處理
  getreadercontext().firealiasregistered(name, alias, extractsource(ele));
 }
 }
}

首先對 alias 標簽屬性進行提取校驗,校驗通過后進行別名注冊,別名注冊和 bean 標簽解析中的別名注冊一直,此處不再贅述

import 標簽解析

?
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public class defaultbeandefinitiondocumentreader {
 protected void importbeandefinitionresource(element ele) {
 // 獲取import標簽的resource屬性
 string location = ele.getattribute(resource_attribute);
 // 如果不存在則不做任何處理
 if (!stringutils.hastext(location)) {
  getreadercontext().error("resource location must not be empty", ele);
  return;
 }
 // 解析占位符屬性 格式如"${user.dir}"
 location = getreadercontext().getenvironment().resolverequiredplaceholders(location);
 set<resource> actualresources = new linkedhashset<>(4);
 // 判斷資源是絕對路徑還是相對路徑
 boolean absolutelocation = false;
 try {
  absolutelocation = resourcepatternutils.isurl(location) || resourceutils.touri(location).isabsolute();
 } catch (urisyntaxexception ex) {
  // cannot convert to an uri, considering the location relative
  // unless it is the well-known spring prefix "classpath*:"
 }
 
 // 如果是絕對路徑則直接根據地址加載對應的配置文件
 if (absolutelocation) {
  try {
  int importcount = getreadercontext().getreader().loadbeandefinitions(location, actualresources);
  if (logger.isdebugenabled()) {
   logger.debug("imported " + importcount + " bean definitions from url location [" + location + "]");
  }
  } catch (beandefinitionstoreexception ex) {
  getreadercontext().error("failed to import bean definitions from url location [" + location + "]", ele, ex);
  }
 } else {
  try {
  int importcount;
  // 根據相對路徑加載資源
  resource relativeresource = getreadercontext().getresource().createrelative(location);
  if (relativeresource.exists()) {
   importcount = getreadercontext().getreader().loadbeandefinitions(relativeresource);
   actualresources.add(relativeresource);
  } else {
   string baselocation = getreadercontext().getresource().geturl().tostring();
   importcount = getreadercontext().getreader().loadbeandefinitions(stringutils.applyrelativepath(baselocation, location), actualresources);
  }
  if (logger.isdebugenabled()) {
   logger.debug("imported " + importcount + " bean definitions from relative location [" + location + "]");
  }
  } catch (ioexception ex) {
  getreadercontext().error("failed to resolve current resource location", ele, ex);
  } catch (beandefinitionstoreexception ex) {
  getreadercontext().error("failed to import bean definitions from relative location [" + location + "]", ele, ex);
  }
 }
 // 解析后進行監聽器激活處理
 resource[] actresarray = actualresources.toarray(new resource[actualresources.size()]);
 getreadercontext().fireimportprocessed(location, actresarray, extractsource(ele));
 }
}

完成了對 import 標簽的處理,首先就是獲取 <import resource="beans.xml"/> resource 屬性所表示的路徑,接著解析路徑中的屬性占位符 如 ${user.dir} ,然后判定 location 是絕對路徑還是相對路徑,如果是絕對路徑則遞歸調用 bean 的解析過程(loadbeandefinitions(location, actualresources);) ,進行另一次解析,如果是相對路徑則計算出絕對路徑并進行解析,最后通知監聽器,解析完成

總結

熬過幾個無人知曉的秋冬春夏,撐過去一切都會順著你想要的方向走…

好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。

說點什么

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

原文鏈接:http://blog.battcn.com/2018/01/11/spring/spring-2/

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 久久久久久毛片免费看 | 国产精品1区| 国产成人精品一区二区三区视频 | 北条麻妃一区二区三区中文字幕 | 免费黄色在线 | 亚洲二区视频 | 69久久| 中文字幕日本一区二区 | 久久狠狠| 国产精品成人3p一区二区三区 | 欧美激情在线播放 | 亚洲欧美日韩精品久久亚洲区 | 欧美日韩成人在线观看 | 91在线视频观看 | 成人综合av | 日韩在线播放一区 | 国产伦精品一区二区三区四区视频 | 久久精品六 | 99精品欧美一区二区三区综合在线 | 一级做a| 国产精品久久久久久久福利院 | 精品久久一二三区 | 老熟妇午夜毛片一区二区三区 | 成人片免费看 | 成人美女av | 最新中文字幕在线 | 国产精品久久一区 | 欧美日韩在线电影 | 日本一区二区三区中文字幕 | 日韩成人片 | 国产综合亚洲精品一区二 | 激情视频网 | 久久久精品视频免费观看 | 国产特级毛片aaaaaaa高清 | 国产一区久久 | 国产在线观看一区 | 精品久久国产老人久久综合 | 日本在线一区二区三区 | 亚洲精品在线看 | 成人免费乱码大片a毛片软件 | 国产福利视频在线观看 |