Spring 的運行原理,包括spring如何創建對象(IOC 控制反轉)和將對象的屬性註入(DI 依賴註入)。詳細介紹spring是如何配置各種bean,並且維護bean與bean之間的關係。 ...
上一篇的博客,我們可以看出來,spring可以維護各個bean (對象),並向其中註入屬性值。那麼,如果們要把一個對象的引用註入另外一個對象呢?應該怎麼處理呢?
我們知道,對於對象中的屬性來說,我們註入屬性的方式為:在配置文件中使用property標簽。
<property name="對象屬性名稱" > <value>要註入的內容</value> </property>
那麼如果我們的類中有對另一個對象的引用呢?這個時候,其實類似於註入一個屬性,只是需要使用ref標簽進行註入:首先我們需要通過bean配置兩個類,我們分別給他們的id命名為:類1、類2。這時假如我們的需求是類1中包含有對類2的引用。也就是說,類2是類1的一個屬性。這時我們就需要將類2的對象註入到類1對象中。配置文件中的寫法如下:
<bean id= "類1" class="類1的全路徑"> <!--這裡的註入方法類似於上面的value註入,可以寫在一行也可以多行--> <property name="類2在類1中的屬性名" ref="類2"> </bean> <!--這裡的類2是對象名稱,再註入的時候ref中的值必須和bean 後面的Id完全一致--> <bean id="類2" class="類2的全路徑"> </bean>
以上的做法就是我們的spring管理各個對象和維護各個對象之間的關係。其中具體的執行原理是:
當ClassPathXmlApplicationContext("applicationContext.xml")這句話執行的時候,spring容器對象就被創建。這個對象會讀取applicationContext.xml中配置的bean就會被創建,並且放入記憶體。具體是怎麼創建的呢?依賴於我們的反射機制。
就拿以上代碼來說:首先類1被創建,創建後,假設這個對象在記憶體中的地址為:123對象中對於對象二的引用為(???)。此時的記憶體如下:
然後類2被創建,這時候,類2在對象中的記憶體地址會賦值給類1中相應欄位的引用。具體來說:假設類2的地址為:456這時123對象中的那個對於對象2的引用由(???)改為(456)完成類的依賴註入。此時記憶體如下:
其實,這些對象都存在與applicationContext對象的一個類似於HashMap的引用中。這也是我們為什麼要將applicationContext對象設置為單例的原因。
那麼,spring是如何實現剛纔的那些個調用呢?首先,通過dom4j將我們的配置文件讀取,這時我們就可以解析到所有相關的類的全路徑了。然後,它再利用反射機制通過如下代碼完成類的實例化:類1=Class.forName("類1的全路徑")。這時,我們就得到了類1。(這也是為啥當我們的類的全路徑寫錯了會導致出現classNotfind的錯誤。)
當我們得到了類1以後,通過調用類1的set方法,將屬性給對象進行註入。而且,需要遵循首字母大寫的set規範。例如:我們的類中有個欄位的屬性為name那麼set方法必須寫成setName(name 的首字母要大寫)否則會報一個屬性找不到的錯誤:
1 public void setName(String name){ 2 this.name= name; 3 }
對象創建後,我們將我們的對象id和我們的對象物理地址,一起存入類似於HashMap的容器中,然後呢,我們是如何獲得我們需要的對象,然後執行對象中的方法呢?我們通過getBean的方法,通過對象Id獲得對象的物理地址,得到對象,然後調用對象的方法,完成對方法的調用。