Spring ioc源碼解析這一系列文章會比較枯燥,但是只要堅持下去,總會有收獲,一回生二回熟,沒有第一次,哪有下一次...
本系列目錄:
一、Spring IOC概述
1.1 IOC
Ioc—Inversion of Control,即“控制反轉”,是一種設計思想。在Java開發中,Ioc意味着將你設計好的對象交給容器控制,而不是傳統的在你的對象內部直接控制。
●誰控制誰,控制什么:傳統Java SE程序設計,我們直接在對象內部通過new進行創建對象,是程序主動去創建依賴對象;而IoC是有專門一個容器來創建這些對象,即由Ioc容器來控制對象的創建;誰控制誰?當然是IoC 容器控制了對象;控制什么?那就是主要控制了外部資源獲取(不只是對象包括比如文件等)。
●為何是反轉,哪些方面反轉了:有反轉就有正轉,傳統應用程序是由我們自己在對象中主動控制去直接獲取依賴對象,也就是正轉;而反轉則是由容器來幫忙創建及注入依賴對象;為何是反轉?因為由容器幫我們查找及注入依賴對象,對象只是被動的接受依賴對象,所以是反轉;哪些方面反轉了?依賴對象的獲取被反轉了。
用圖例說明一下,傳統程序設計都是主動去創建相關對象然后再組合起來,如下圖:
當有了IoC/DI的容器后,在客戶端類中不再主動去創建這些對象了,如下圖:
1.2 DI
DI—Dependency Injection,即“依賴注入”:組件之間依賴關系由容器在運行期決定,形象的說,即由容器動態的將某個依賴關系注入到組件之中。依賴注入的目的並非為軟件系統帶來更多功能,而是為了提升組件重用的頻率,並為系統搭建一個靈活、可擴展的平台。通過依賴注入機制,我們只需要通過簡單的配置,而無需任何代碼就可指定目標需要的資源,完成自身的業務邏輯,而不需要關心具體的資源來自何處,由誰實現。
理解DI的關鍵是:“誰依賴誰,為什么需要依賴,誰注入誰,注入了什么”,那我們來深入分析一下:
●誰依賴於誰:當然是應用程序依賴於IoC容器;
●為什么需要依賴:應用程序需要IoC容器來提供對象需要的外部資源;
●誰注入誰:很明顯是IoC容器注入應用程序某個對象,應用程序依賴的對象;
●注入了什么:就是注入某個對象所需要的外部資源(包括對象、資源、常量數據)。
1.3 IOC和DI關系
IoC和DI由什么關系呢?其實它們是同一個概念的不同角度描述,由於控制反轉概念比較含糊(可能只是理解為容器控制對象這一個層面,很難讓人想到誰來維護對象關系),所以2004年大師級人物Martin Fowler又給出了一個新的名字:“依賴注入”,相對IoC 而言,“依賴注入”明確描述了“被注入對象依賴IoC容器配置依賴對象”。
二、核心類源碼解讀
2.1 Spring IOC容器接口設計
Spring框架中,一旦把一個bean納入到Spring IoC容器之中,這個bean的生命周期就會交由容器進行管理,一般擔當管理者角色的是BeanFactory或ApplicationContext。下面來看一下IOC容器接口設計,如下圖(默認JDK8):
如上圖,可見主要有兩條主線:
1.基本容器:BeanFactory-》HierarchicalBeanFactory-》ConfigurableBeanFactory
- BeanFactory接口定義了基本的Ioc容器的規范,包括getBean()這樣的Ioc容器的基本方法(通過這個方法可以從容器中取得Bean)。
- HierarchicalBeanFactory增加了getParentBeanFactory()的接口功能,使BeanFactory具備了雙親Ioc容器的管理功能。
- ConfigurableBeanFactory定義了一些配置功能,比如通過setParentBeanFactory()設置雙親Ioc容器,通過addBeanPostProcessor()配置Bean后置處理器,等等。
2.高級容器:BeanFactory-》ListableBeanFactory-》ApplicationContext-》WebApplicationContext/ConfigurableApplicationContext
- ListableBeanFactory細化了許多BeanFactory的接口功能,比如定義了getBeanDefinitionNames()接口方法;
- ApplicationContext接口,它通過繼承MessageSource、ResourcePatternResolver、ApplicationEventPublisher接口,在BeanFactory簡單Ioc容器的基礎上添加了許多對高級容器的特性支持。
2.2 BeanFactory接口
尊重源碼,以下摘自BeanFactory源碼注釋翻譯:
BeanFactory是獲取spring bean容器的頂級接口。該接口被持有一系列bean definitions的對象所實現。依賴bean definitions,工廠返回一個原型實例或者一個單例實例。
通常,BeanFactory將加載存儲在配置中的bean definitions資源(例如XML文檔)。這些定義沒有限制何種方式存儲:LDAP, RDBMS, XML,properties file等。並且鼓勵使用bean的依賴注入引用。
實現類需要支持Bean的完整生命周期,完整的初始化方法及其標准順序(格式:接口 方法)為:
1.BeanNameAware setBeanName 設置bean名稱
2.BeanClassLoaderAware setBeanClassLoader 設置bean類加載器
3.BeanFactoryAware setBeanFactory 設置bean工廠
4.EnvironmentAware setEnvironment 設置環境:profiles+properties
5.EmbeddedValueResolverAware setEmbeddedValueResolver 設置嵌入式值解析器
6.ResourceLoaderAware setResourceLoader 設置資源載入器,只適用於在應用程序上下文中運行
7.ApplicationEventPublisherAware setApplicationEventPublisher注入應用事件發布器ApplicationEventPublisher
8.MessageSourceAware setMessageSource 設置國際化支持
9.ApplicationContextAware setApplicationContext 設置應用上下文
10.ServletContextAware setServletContext 設置servlet上下文
11.BeanPostProcessors postProcessBeforeInitialization 執行bean處理器前置方法
12.InitializingBean afterPropertiesSet 執行初始化Bean設置完屬性后置方法
13.a custom init-method definition 執行自定義初始化方法
14.BeanPostProcessors postProcessAfterInitialization 執行bean處理器后置方法
銷毀順序:
1.DestructionAwareBeanPostProcessors postProcessBeforeDestruction 銷毀處理器的前置方法
2.DisposableBean destroy Bean銷毀回調方法
3.a custom destroy-method definition 用戶自定義銷毀方法
關於Spring bean 生命周期的驗證,飛機票:Spring bean 生命周期驗證
下面來看一下BeanFactory接口源碼:
1 public interface BeanFactory { 2 3 //轉定義符 4 String FACTORY_BEAN_PREFIX = "&"; 5 6 //定義5種獲取Bean方法 7 Object getBean(String name) throws BeansException; 8 <T> T getBean(String name, Class<T> requiredType) throws BeansException; 9 <T> T getBean(Class<T> requiredType) throws BeansException; 10 Object getBean(String name, Object... args) throws BeansException; 11 <T> T getBean(Class<T> requiredType, Object... args) throws BeansException; 12 13 //判斷容器是否含有指定名字的Bean 14 boolean containsBean(String name); 15 16 //查詢指定名字的Bean是否是Singleton類型的Bean. 17 boolean isSingleton(String name) throws NoSuchBeanDefinitionException; 18 19 //查詢指定名字的Bean是否是Prototype類型的 20 boolean isPrototype(String name) throws NoSuchBeanDefinitionException; 21 22 //查詢指定了名字的Bean的Class類型是否是特定的Class類型. 23 boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException; 24 boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException; 25 26 //查詢指定名字的Bean的Class類型. 27 Class<?> getType(String name) throws NoSuchBeanDefinitionException; 28 29 //查詢指定了名字的Bean的所有別名,這些都是在BeanDefinition中定義的 30 String[] getAliases(String name); 31 32 }
2.3 XmlBeanFactory實現類
spring3.1之后推薦直接使用:DefaultListableBeanFactory+XmlBeanDefinitionReader(第三節有樣例)。雖然這個類已廢棄,但不妨礙我們來簡單理解一下
1 @Deprecated 2 @SuppressWarnings({"serial", "all"}) 3 public class XmlBeanFactory extends DefaultListableBeanFactory { 4 5 private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this); 6 //載入資源構造 7 public XmlBeanFactory(Resource resource) throws BeansException { 8 this(resource, null); 9 } 10 //通過載入資源和父類的BeanFactory構造 11 public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException { 12 super(parentBeanFactory); 13 this.reader.loadBeanDefinitions(resource); 14 } 15 16 }
1.在XmlBeanFactory中實例化了一個XmlBeanDefinitionReader,這個Reader對象就是用來處理以xml形式的持有類信息的BeanDefinitionl類。
2.BeanDefinitionl信息封裝成Resource,作為構造入參
3.調用reader的loadBeanDefinitions,完成容器的初始化和注入。
2.4 模擬容器獲取Bean
1 public static void main(String[] args) { 2 //1.容器IOC獲取bean初始化 3 ClassPathResource resource = new ClassPathResource("spring.xml");//載入資源 4 DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); 5 XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);//構造reader 6 reader.loadBeanDefinitions(resource);//核心方法,解析bean定義 7 Dao dao = factory.getBean("daoImpl", Dao.class);//IOC容器DefaultListableBeanFactory通過名稱和類class獲取bean單例對象 8 dao.select();//執行Bean實例方法 9 }
spring.xml中就寫一行:定義一個Bean即可
<bean id="daoImpl" class="spring.aop.xml.dao.impl.DaoImpl" />
三、總結
本文概述IOC/DI 原理並分析了Spring核心接口設計,最后結合一個簡單例子,模擬了最簡單的容器DefaultListableBeanFactory從xml載入bean定義並生成bean對象的過程讓大家有一個大體的認知。
下一章,我們將分析容器初始化。
=======================
參考
http://www.zzcode.cn/springioc/thread-39.html