總結對SpringIOC源碼的理解

總結對SpringIOC的理解

一.IOC定義

  • IOC是控制翻轉,程序提供依賴關係給Spring,由Spring來維護依賴關係
  • 類的產生過程交由Spring容器
  • 將產生的實例對象,通過DI注入

IOC是目標,DI依賴注入是手段
IOC思想是: 一個實例的產生就不應該由程序員自己new出來,而是如果你需要代理類,就創建一個代理類對象傳給你;如果你僅僅需要類的實例對象,那麼就創建一個對象注入給你

二.預備概念

1.beanFactory和factoryBean區別

  • beanFactory是Spring的bean工廠,用來產生bean的
  • factoryBean本身是一個Bean,是由Spring管理的對象;當一個類依賴關係很複雜時,可以使用factoryBean,不用自己來維護依賴關係。

比如:Mybatis提供了sqlSessionFactoryBean對象,該對象可以返回給Spring一個sqlSessionFactory對象,Spring拿到該對象可以直接創建會話,至於依賴關係,由Mybatis維護好。

2.beanDefinition

  • beanDefinition與Bean的關係就好比java中的類與class字節碼的關係
  • Java中的類是對象,使用class類來描述(類名、類的方法、類的成員變量等)
  • Bean也是Java中的對象,只不過Bean比類更豐富,它不僅有常規屬性,還有別的屬性(單例、懶加載)等,這些特點class無法描述。所以使用BeanDefinition把Bean的屬性抽象出來

3.BeanFactoryPostProcessor後置處理器

  • 後置處理器,是Spring的擴展點之一;
  • 在任意Bean被實例化之前,程序會執行程序員自定義(實現了該接口的類)的後置處理器和Spring中自帶的後置處理器
  • 後置處理器的作用是:可以按照自己需求在bean創建之前定義bean屬性、創建之後初始化、自定義注入方式等

比如:aop實現,就是通過後置處理器(下一篇會介紹)
再比如:DI依賴注入,Spring默認是@AutoWired通過java反射注入類的元數據。可以通過自定義類實現後置處理器接口,修改自動注入屬性模型,採用構造方法注入或setter()注入。
再比如:bean的生命週期的過程,在9個地方使用了5種不同的後置處理器,來處理對象實例化前後過程以及實例的屬性設置

三.IOC源碼分析

1.構造Spring容器

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class)

  • 三種創建Spring容器的方法
    AnnotationConfigApplicationContext
    ClassXmlApplicationContext
    FileSystemXmlApplicationContext

  • Spring容器的理解
    從微觀上:spring容器即存放beanDefinition的beanDefinitionMap容器(本質是ConcurrentHashMap)
    從宏觀上:即整個Spring環境(類似你要建造一個廠子,首先需要選址落地,容器即整個大環境)(大環境裏面包括:工廠beanFactory用來產生Bean、Reader解析器將類抽象成beanDefinition、Registry註冊器將beanDefinition put至beanDefinitionMap中、BeanPostProcessor後置處理器對Spring進行擴展)

2.配置Spring容器環境-讀取器、註冊器、原材料

2.1-this()構造方法中

new AnnotatedBeanDeflinitionReader()
  • 使用AnnotatedBeanDeflinition來修飾被加了@直接的BeanDeflinition;
  • Reader是beanDefinition讀取器:給定一個Java類,通過Reader可以將其抽象爲BeandDefinition對象

2.2-register()

  • Java類被Reader抽象爲BeanDefinition後,會被BeanDifinitionRegistry的registry()註冊(map.put())至beanDefinitionMap中去。
  • 被put至BeanDefinitionMap中的BeanFefinition對象,就是後續Spring工廠BeanFactory加工(創建=實例化)對象的原材料。

3.初始化Spring環境

refresh()
  • 通過1.之後,Spring已經創建了BeanFactory工廠框架,裏面有基本的beanDefinitionMap等
  • 通過2.之後,工程BeanFactory已經包含beanDefinition了,此時可以準備初始化工廠了
3.1 通知BeanFactory使用上下文類加載器
3.2 爲工廠添加後置處理器
  • 兩種後置處理器:程序員實現接口自定義的、Spring中自帶的;
  • 其中SpringAop等過程在此期間完成
  • 執行完後置處理器後,此時beanDefinitionMap中已經有7個beanDefinition對象。其中就有我們的啓動類AppConfig
  • 接下來Spring會遍歷這7個beanDefinition,解析他們是否加了@註解;如果加了註解,判斷加了什麼註解

3.3啓動類AppConfig註解@解析

  • 判斷這7個beanDefinition是否加了下面四個註解:@Configuration、@ComponentScan、@Component、@Import
  • 如果加了Configuration註解,則不用再去判斷是否加了其他三個註解,直接執行doScan()方法
  1. 通過scan掃描basePackage路徑下的我們書寫的.java文件(XXXController、ServiceImp等),將符合條件的類通過Reader讀取器抽象爲BeanDefinition
  2. 將這些beanDefinition對象放入set中
  3. 等到所有掃描完成後,會統一遍歷set集合中的beanDefinition對象,查看他們的基本屬性以及是否添加了下面註解:@Component、@Controller、@Service、@Repository。如果加了這些註解,則將這些beanDefinition對象,從set中取出來,通過Registry註冊(put)至BeanDefinitionMap中。

3.4 實例化對象-Spring中Bean的生命週期

工廠環境搭建好了,生產實例化對象的原材料beanDefinition也全部放入map中了,接下來實例化單例對象
  1. 第一處後置處理器:解析aop切面信息,然後將切面類抽象的beanDefinition對象放入單例池map中緩存
  2. 第二處後置處理器:通過反射調用選出的構造方法(此處選出構造方法過程很複雜)創建對象,放入SingleFactory中
  3. 第三處後置處理器:通過構造方法方式,注入實例對象
  4. 第四處後置處理器:處理循環引用
public class ServiceImp{
     @AutoWired
      private Dao dao;	
  }
public class DaoImp{
     @AutoWired
      private Service service;	
  }
  • 創建serviceImp實例對象後,先將其放入SingleFactory中;
  • 發現serviceImp中有一個Dao屬性,通過ByName或者ByType方式找到Dao類型,調用getBean(dao)
  • 同理實例化DaoImp後,將其放入SingleFactory中,也同樣發現了有一個Service屬性,通過ByName或ByType方式找到S而vice類型,調用getBean(service)
  • 執行上述getBean(service)後,會去SingleFactory中拿Service實例;首先將Service實例對象從SingleFactory中刪除,放入SingleObject中;然後通過反射的方式,獲取該service實例的mateData元數據;最後通過Field.set(dao,service)將service實例對象信息注入給dao對象
  • 此時dao實例對象創建結束;再執行Field.set(service,dao)將dao實例對象的元數據信息注入給service實例對象,至此完成了循環引用問題

5…第五處後置處理器:判斷bean是否需要完成屬性填充
6.第六處後置處理器:完成bean屬性填充=>依賴注入
7.第七處後置處理器:即bean實例初始化之前,前置處理器
8.第八處後置處理器:即bean實例初始化之後,後置處理器
9.第九處後置處理器:destory銷燬Bean實例

3.5注入實例化對象

經過3.4已經實例化對象了,準備採用DI依賴注入對象

首先Spring中的依賴注入分爲三種:構造方法、setter方法、Java反射方式

  • Spring默認方式是採用的@Autowired通過Java反射注入
  • 可以自定義後置處理器,不採用@Autowired方式,而是通過setter()方法方式注入;
  • 在bean還未實例化之前,通過implement BeanfactoryPostProcessor接口,將Bean注入模型修改爲setter(),這樣可以在注入是完全擺脫@AutoWired,減少對Spring的依賴
	public class MyBeanPostProcessor implements BeanFactoryProcessor{
		xxx;
		setAutoWiredMode(2);//默認是2
		//@Autowired默認值爲0;
		//構造方法:1
		//setXxx()方法:2
	}
  1. 在實例化對象A後,發現對象中依賴類B
  2. 通過ByName或ByType找到依賴對象類型
  • ByName缺點是:
    <bean id=“dao1” class=“DaoImp”
    <bean id=“dao2” class=“DaoImp”

A類實例對象去找依賴時,從map中找到了兩個Dao類型的實例對象,A對象不知道使用哪一個,會報錯

  • ByType:根據構造方法SetXxx(),將set去掉,然後將構造方法名第一個大寫字母小寫,即:xxx來找類型

3… 找到依賴對象類型後,調用getBean(B)方法;從SingleFactory中拿到該類型實例對象
4… 通過反射方式獲取該實例類的元數據信息
5… 通過Field.set(A,B)方法,將B實例對象通過Spring默認的@AutoWired Java反射方式注入到A實例對象中;至此,SpringIOC控制翻轉完成~

在經歷了創建BeanFactory->準備配置工廠Reader、Registry->refresh初始化工廠,將實例化對象的加了@註解的原材料beanDefinition都加入map中->實例化對象(涉及Bean的生命週期)->Java反射方式完成依賴注入,實現IOC

後續:如果錯誤希望指正~
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章