本來是在debug dubbo的reference bean的init()過程,因為ReferenceBean是繼承了Spring FactoryBean介面的,
所以初始化入口自然就是FactoryBean定義的函式,getObject()。在該方法內,只顯示呼叫了ReferenceConfig.get()。
內容如下:
public synchronized
複製程式碼
可以看到,核心的初始化程式碼就在init()中。這裡,會首先判斷factoryBean 要建立的bean例項ref是否已經初始化,若未初始化,才會進行Init()呼叫。
所以,我斷點自然就打在ReferenceBean.getObject()上。
啟動spring。
反覆多次,我發現,只要我在ReferenceBean.getObject()或者ReferenceConfig.get()上加上斷點,ref例項就會莫名其妙地已經被初始化過,proxy$xxxx。
這就奇怪了。
這個ReferenceBean的整個的入口函式,getObject()的觸發,是在我的控制下的啊,即:
springContext.getBean("referenceBeanId");
那我就在想,是不是spring container的初始化有非同步的部分呢?所以我就直接把斷點載入init()方法上。
然後我返回撥試後發現,如果我只將斷點加在Init(),而ReferenceBean.getObject()與ReferenceConfig.get()不加斷點的話,init()方法裡是正常進入,且進入的程式碼initialized也是false的
private void
複製程式碼
}
複製程式碼
就是init()開頭4行程式碼處。
後來我就想,是不是哪裡給反射注入了呢?當然,我也沒啥發現,我就直接百度了。結果果不其然。
在網上發現了一篇同樣問的文章。那個人在原始碼里加了一段註釋,如下
圖片已損壞
圖片已損壞
可以看到,AbstractConfig.toString()方法竟然反射呼叫了ReferenceConfig.init()方法。。。
AbstractConfig.toString()的程式碼如下:
可以看到,這個if裡是對所有getter通過的,通過後,又再接下來的紅框處呼叫了我擦,也就是說,ReferenceBean.getObject()給呼叫了,進而也就init()給呼叫了。
後來,原文作者又做了這樣一個測試,得出了最終結果
圖片已損壞
結果就是:
IDEA這類編輯器的debug功能為了在斷點處能夠顯示類例項的相關資訊,就會反射呼叫相關類例項的toString()方法!!!!
思考:
DUBBO為什麼要在AbstractConfig.toString()的反射呼叫init()呢?真尼瑪奇怪。。。。
答案:
dubbo的AbstractConfig的toString方法反射呼叫只是為了輸出時能夠更全面一點。但是因為AbstractConfig的子類
ReferenceBean實現了FactoryBean介面,這個介面是Spring用來獲取Bean例項的工廠bean,生成bean的方法就叫getObject,正好符合了toString裡面邏輯,而getObject裡是要初始化bean的。所以,就這麼巧地對應上了