Spring IOC(一)概覽
正文
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