作者:zuoxiaolong8810(左瀟龍),轉載請注明出處,特別說明:本博文來自博主原博客,為保證新博客中博文的完整性,特復制到此留存,如需轉載請注明新博客地址即可。
上一章當中我沒有提及具體的搭建環境的步驟,一個是不得不承認有點懶,另外一個我覺得如果上章所述的那些環境都還不會搭建的話,研究spring的源碼還有些過早。
如果你有興趣的話,相信已經搭建好了學習研究的環境,接下來就可以進入正題了。
網上也有很多關於spring源碼學習的文章以及帖子,講的也都不錯,但是有些可能高估了讀者的能力,該深入的地方反倒一句帶過,我現在也是在一步一步研究,和大家的進度一樣,所以可能在我的角度來和各位探討,更加容易。
首先我們來說一下IOC,IOC是spring最核心的理念,包括AOP也要屈居第二,那么IOC到底是什么呢,四個字,控制反轉。
網上有不少是這么解釋IOC的,說IOC是將對象的創建和依賴關系交給容器,這句話我相信不少人都知道,在我個人的理解,IOC就是讓我們的開發變的更簡單了。
為什么這么說呢,光說沒意思,直接上代碼。
public class Person { public void work(){ System.out.println("I am working"); } }
上面這個是Person類,如果我們還有一個Company公司類,公司要開張需要人來工作,所以我們可能需要這樣。
public class Company { public Person person; public Company(Person person){ this.person = person; } public void open(){ person.work(); System.out.println("I am opening"); } }
好了,這樣可以了,雖說和現實有些區別,畢竟沒有一個人的公司,但是就是這么個意思。必須要有人在公司里,公司才能開張。
有了spring上述情況我們是怎么寫的呢?Person類不變,Company就可以簡單些了。
public class Company { @Autowired public Person person; public void open(){ person.work(); System.out.println("I am opening"); } }
OK了,使用注解后,spring里的寫法是這樣的,是不是簡單很多?或許你可能會說,這才減少了多少代碼,但是事實上是,真正的項目中,不可能有這么簡單的依賴關系,或許是2層,3層甚至N層。
當然,可能我們有時候用的XML,XML和注解的區別就在於這里,注解可以快速的完成依賴的注入,但是缺點也很明顯,那就是比如我公司里不需要人了,我需要的是機器,那么我還要手動改代碼,將Person換成機器(這里應該是英文,英語不好,懶得查了,只記得念“磨洗”),而如果是XML配置,那么我們只需要改下配置文件就可以。維護起來會方便很多,當然XML的缺點也很明顯,那就是依賴關系復雜的時候,XML文件會比較臃腫,所以我們一般的做法是將XML分離開來。
說到這里,有些扯遠了,但是我覺得以上可以足夠說明IOC的好處,知道了IOC的好處,我們自然就要知道怎么來實現IOC了。
或許看了spring的源碼,第一感覺是很蒙,包太多,我也很蒙,但是研究東西就是得沉下心來,先來關注一下這個接口,BeanFactory,附上代碼。
package org.springframework.beans.factory; import org.springframework.beans.BeansException; /* * @author Rod Johnson * @author Juergen Hoeller * @since 13 April 2001 */ public interface BeanFactory { String FACTORY_BEAN_PREFIX = "&"; Object getBean(String name) throws BeansException; <T> T getBean(String name, Class<T> requiredType) throws BeansException; <T> T getBean(Class<T> requiredType) throws BeansException; Object getBean(String name, Object... args) throws BeansException; boolean containsBean(String name); boolean isSingleton(String name) throws NoSuchBeanDefinitionException; boolean isPrototype(String name) throws NoSuchBeanDefinitionException; boolean isTypeMatch(String name, Class targetType) throws NoSuchBeanDefinitionException; Class<?> getType(String name) throws NoSuchBeanDefinitionException; String[] getAliases(String name); }
這個便是spring核心的Bean工廠定義,上面的author說是2001年寫的,已經歷史久遠了,這個類是spring中所有bean工廠,也就是俗稱的IOC容器的祖宗,各種IOC容器都只是它的實現或者為了滿足特別需求的擴展實現,包括我們平時用的最多的ApplicationContext。從上面的方法就可以看出,這些工廠的實現最大的作用就是根據bean的名稱亦或類型等等,來返回一個bean的實例。
一個工廠如果想擁有這樣的功能,那么它一定需要以下幾個因素:
1.需要持有各種bean的定義,否則無法正確的完成bean的實例化。
2.需要持有bean之間的依賴關系,否則在bean實例化的過程中也會出現問題。例如上例,如果我們只是各自持有Person和Company,卻不知道他們的依賴關系,那么在Company初始化以后,調用open方法時,就會報空指針。這是因為Company其實並沒有真正的被正確初始化。
3.以上兩種都要依賴於我們所寫的依賴關系的定義,暫且認為是XML文件(其實可以是各種各樣的),那么我們需要一個工具來完成XML文件的讀取。
我目前想到的,只需要滿足以上三種條件,便可以創建一個bean工廠,來生產各種bean。當然,spring有更高級的做法,以上只是我們直觀的去想如何實現IOC。
其實在上述過程中仍舊有一些問題,比如第一步,我們需要持有bean的定義,如何持有?這是一個問題。我們知道spring的XML配置文件中,有一個屬性是lazy-init,這就說明,bean在何時實例化我們是可以控制的。這個屬性默認是false,但是我們可以將這個屬性設置為true,也就是說spring容器初始化以后,配置了延遲加載的各種bean都還未產生,它們只在需要的時候出現。
所以我們無法直接的創建一個Map<String,Object>來持有這些bean的實例,在這里要注意,我們要儲存的是bean的定義,而非實例。
那么接下來,又是一個祖宗級別的接口要出現了,來看BeanDefinition。
package org.springframework.beans.factory.config; import org.springframework.beans.BeanMetadataElement; import org.springframework.beans.MutablePropertyValues; import org.springframework.core.AttributeAccessor; public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement { String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON; String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE; int ROLE_APPLICATION = 0; int ROLE_SUPPORT = 1; int ROLE_INFRASTRUCTURE = 2; String getParentName(); void setParentName(String parentName); String getBeanClassName(); void setBeanClassName(String beanClassName); String getFactoryBeanName(); void setFactoryBeanName(String factoryBeanName); String getFactoryMethodName(); void setFactoryMethodName(String factoryMethodName); String getScope(); void setScope(String scope); boolean isLazyInit(); void setLazyInit(boolean lazyInit); String[] getDependsOn(); void setDependsOn(String[] dependsOn); boolean isAutowireCandidate(); void setAutowireCandidate(boolean autowireCandidate); boolean isPrimary(); void setPrimary(boolean primary); ConstructorArgumentValues getConstructorArgumentValues(); MutablePropertyValues getPropertyValues(); boolean isSingleton(); boolean isPrototype(); boolean isAbstract(); int getRole(); String getDescription(); String getResourceDescription(); BeanDefinition getOriginatingBeanDefinition(); }
顧名思義,這個便是spring中的bean定義接口,所以其實我們工廠里持有的bean定義,就是一堆這個玩意,或者是他的實現類和子接口。這個接口並非直接的祖宗接口,他所繼承的兩個接口一個是core下面的AttributeAccessor,繼承這個接口就以為這我們的bean定義接口同樣具有處理屬性的能力,而另外一個是beans下面的BeanMetadataElement,字面翻譯這個接口就是bean的元數據元素,它可以獲得bean的配置定義的一個元素。在XML文件中來說,就是會持有一個bean標簽。
仔細觀看,能發現beanDefinition中有兩個方法分別是String[] getDependsOn()和void setDependsOn(String[] dependsOn),這兩個方法就是獲取依賴的beanName和設置依賴的beanName,這樣就好辦了,只要我們有一個BeanDefinition,就可以完全的產生一個完整的bean實例。
今天就先到這里吧,我也是邊看邊寫的,與其說跟我一起學,其實這個系列的應該叫源碼學習筆記,更多的還是看到哪里,寫到哪里,談不上跟我一起學。
如果文中有不周到的地方,希望各位盡管指出。