Spring IOC(一)概覽


Spring ioc源碼解析這一系列文章會比較枯燥,但是只要堅持下去,總會有收獲,一回生二回熟,沒有第一次,哪有下一次...

本系列目錄:

Spring IOC(一)概覽

Spring IOC(二)容器初始化

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

談談對Spring IOC的理解


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM