javascript
中getname_Spring IOC中的灵魂伴侣:BeanFactory ApplicationContext
推薦閱讀:
- 手撕分布式技術:限流、通訊、緩存,全部一鍋端走送給你
- 秋招面試總結:Java+并發+Spring+MySQL+分布式+Redis+算法+JVM等
- Spring全家桶筆記:Spring+Spring Boot+Spring Cloud+Spring MVC
BeanFactory & FactoryBean
說起Spring中的靈魂伴侶難道不是BeanFactory與FactoryBean嗎?ta們兩個不僅長相相似,在面試題目中更是形影不離,成雙成對。然而事實上二者的關系就像生命中的過客,只是匆匆一眼,便相忘于江湖。 不過FactoryBean并不孤單,遠處的ObjcetFactory遙遙相望,本文中并不準備詳細解析這兩個接口,不過讀者可以把他們兩個理解為指定類型Bean的孵化器,我們可以通過這兩個接口改變Bean的初始化行為。但是二者還是有很大區別的。
BeanFactory & ApplicationContext
日常工作中我們常常將BeanFactory稱為容器,而將ApplicationContext稱為上下文。不知大家究竟有沒有思考過二者之間的關系。Spring Aware接口家族一文中我曾詳細闡釋過如何獲取當前運行環境中的BeanFactory、ApplicationContext,我們不妨在代碼中找尋答案。
- 配置類
- 獲取二者信息
- 啟動類
- 結果
顯而易見二者不僅不是一個對象,類型都不一樣。看到這里大多數人的認知已經破碎,因為潛意識中他們認為二者其實是一個事物。事實上人家甚至連繼承關系都沒有,直接打碎了另一波人的幻想。不信我們看看二者的UML類圖。
幾個容器?
敏銳的人其實已經發現了矛盾,認知中Spring的根容器應該有且只有一個才合理。但是這分明就是兩個沒有什么關聯的對象啊。Spring官方文檔如此論述二者的關系:
簡而言之,BeanFactory提供了配置框架和基本功能,ApplicationContext增加了更多針對企業的功能。ApplicationContext是BeanFactory的一個完整的超集。
按照官方的解釋:二者是一個包含與被包含的關系,那么在ApplicationContext中我們可以獲得根容器嗎? 上帝說:要有光,于是getAutowireCapableBeanFactory()就來了。
package com.spring.container;import org.springframework.beans.BeansException;import org.springframework.beans.factory.BeanFactory;import org.springframework.beans.factory.BeanFactoryAware;import org.springframework.beans.factory.config.AutowireCapableBeanFactory;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.stereotype.Component;/** * @Author: Raphael */@Componentpublic class SpringIoc implements BeanFactoryAware, ApplicationContextAware { private BeanFactory beanFactory; @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; System.err.println(System.identityHashCode(beanFactory)); System.out.println(beanFactory.getClass().getName()); } // 直接打印兩個對象的比對結果 @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory(); System.err.println(factory.hashCode()); System.out.println(factory.getClass().getName()); System.out.println("二者相等嗎: " + (factory == beanFactory)); }}驗證結果完全支持官方說明。
DefaultListableBeanFactory
官方對他如此定義:
Spring的{@link ConfigurableListableBeanFactory},{@link BeanDefinitionRegistry}的默認實現 成熟的bean工廠 基于bean定義元數據,可通過后處理器進行擴展
臺前光亮的是BeanFactory,負重前行的卻是DefaultListableBeanFactory,明明是三個人的電影,我卻始終不能有姓名。那么DefaultListableBeanFactory的對象是何時產生的呢?一個新的問題又縈繞在我的心頭。答案其實與IOC容器的初始化密不可分,我在這里不詳敘了。我們只簡單的剖析一下DefaultListableBeanFactory產生對象的心路歷程。 我們在MainContainer中調用了如下構造方法:
public AnnotationConfigApplicationContext(Class>... annotatedClasses) { this(); register(annotatedClasses); refresh();}因為AnnotationConfigApplicationContext繼承了GenericApplicationContext,所以父類的的構造方法也會同時調用,容器對象就在此時誕生。
public GenericApplicationContext() { this.beanFactory = new DefaultListableBeanFactory();}然后refresh()調用obtainFreshBeanFactory()。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); return getBeanFactory();}getBeanFactory()是AbstractApplicationContext定義的抽象方法。又由GenericApplicationContext實現。
public final ConfigurableListableBeanFactory getBeanFactory() { return this.beanFactory;}這里其實就是將自己構造方法產生的對象返回給AnnotationConfigApplicationContext。追蹤到這一層的時候,容器對象的身世之謎才終于被我們揭開。其實ApplicationContext之所以有Beanfactory能力就是因為有關容器的操作他都委托給自己內部的容器對象了。舉個例子:
public T getBean(String name, Class requiredType) throws BeansException { assertBeanFactoryActive(); return getBeanFactory().getBean(name, requiredType);}這里實際上他并沒有對此方法有詳細的實現,而是通過getBeanFactory()獲取自身內部的容器對象,然后交由ta實現。 現在脈絡應該足夠清晰了。Spring源碼是設計模式的集大成者,這里其實運用的就是組合模式。
二者差異
其實官方有他們二者的總結
org.springframework.beans和org.springframework.context包是Spring框架的IoC容器的基礎。BeanFactory 接口提供了一種高級配置機制,能夠管理任何類型的對象。 ApplicationContext 是其子接口。
增加了以下特性:
- 與Spring的AOP功能輕松集成
- 消息資源處理(用于國際化)
- 活動發布
- 應用層特定的上下文
作者:顏如玉
鏈接:https://juejin.im/post/5e3ea6c16fb9a07cb427c5b4
總結
以上是生活随笔為你收集整理的中getname_Spring IOC中的灵魂伴侣:BeanFactory ApplicationContext的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 重启sshd_调整linux服务器ssh
- 下一篇: 手机之间如何在局域网下共享文件手机之间如