DefaultNamespaceHandlerResolver中handlerMappings如何初始化

前言:最近一直在看Spring源碼,今天在調試的時候發現一個小問題:在註冊bean時,須要初始化spring默認命名空間處理器,具體在DefaultNamespaceHandlerResolver中實現,可是當Debug時,發現handlerMappings已經賦值,頓感奇怪。經過調試發現了該問題產生的緣由,遂記錄下來。spring


1.調用入口

spring的代碼調用鏈很是的龐大,所以閱讀源碼的時候,也很是耗時,這裏給出建立DefaultNamespaceHandlerResolver的調用入口。安全

2.Debug時出現的現象

在上圖537行處打一斷點,運行後結果以下:app

注意this對象中拋出了異常,此時handlerMappings還爲null,this中拋出的異常信息以下:ide

此異常說明在Debug的時候,調用了toString()方法,但此時DefaultNamespaceHandlerResolver還未初始化完,因此拋出異常。猜想爲IDEA另起了一個線程調用了toStirng()方法。繼續調試代碼。函數

此時斷點在構造函數括號處,程序還未執行完,此時this對象處未拋異常了,handlerMappings還爲null。查看this中的信息。this

生成空間處理器的鍵值對。繼續調試程序,退出DefaultNamespaceHandlerResolver構造函數。idea

此時handlerMappings已經有9個值了,說明對其進行了初始化。根據上面的調試信息,查看DefaultNamespaceHandlerResolver的toString()方法。spa

可見在toString()方法中調用了getHandlerMappings方法。線程

注:該代碼是否是很熟悉,使用了Double-Check的方式避免非線程安全問題,爲單例模式的一種實現形式,是否是很神奇,spring源碼中應用了Double-Check。3d

3.我的理解

當在DefaultNamespaceHandlerResolver初始化過程當中打斷點並利用IDEA進行調試的時候,IDEA會自動開啓一個線程調用該類的toString方法,在本例中就對handlerMappings進行了初始化;若是正常run的方式運行,是不會出現這種狀況的。

對於重寫了toString方法的類,在用Debug調試時會出現上述的狀況,可寫簡單代碼進行驗證,具體代碼以下:

 1 public class ToStringTest {
 2     /**
 3      * 驗證Debug時,idea會開啓一個線程調用對象的toString方法
 4      */
 5     public static void main(String[] args) {
 6 
 7         WilltoStringInvoked will = new WilltoStringInvoked();
 8 
 9         System.out.println("若是在這裏設置斷點,則輸出1");
10 
11         System.out.println(will.getValue());
12 
13         System.out.println("若是不設置斷點,則輸出0");
14 
15     }
16 
17     static class WilltoStringInvoked {
18         private volatile int value = 0;
19 
20         private int setValue() {
21             if (value == 0) {
22                 synchronized (this) {
23                     if (value == 0) {
24                         value = 1;
25                     }
26                 }
27             }
28             return value;
29         }
30 
31         public int getValue() {
32             return value;
33         }
34 
35         @Override
36         public String toString() {
37             return "This value is:" + setValue();
38         }
39     }
40 }

在第9行處設置斷點,Debug結果以下:

若是不設置斷點,調試結果以下:

總結

在調試spring源碼的時候,最開始出現該問題覺時以爲很難以想象,後面經過不斷的調試,猜想出該結論,並進行驗證;同時以爲spring真的很是強大,還需繼續努力,已經看了一段時間了,後面慢慢整理出來,增強印象與理解。


by Shawn Chen,2018.11.22日,下午。

相關文章
相關標籤/搜索