提及Spring中的靈魂伴侶難道不是BeanFactory與FactoryBean嗎?ta們兩個不只長相類似,在面試題目中更是如影隨行,成雙成對。然而事實上兩者的關係就像生命中的過客,只是匆匆一眼,便相忘於江湖。
不過FactoryBean並不孤單,遠處的ObjcetFactory遙遙相望,本文中並不許備詳細解析這兩個接口,不過讀者能夠把他們兩個理解爲指定類型Bean的孵化器,咱們能夠經過這兩個接口改變Bean的初始化行爲。可是兩者仍是有很大區別的。html
平常工做中咱們經常將BeanFactory稱爲容器,而將ApplicationContext稱爲上下文。不知你們究竟有沒有思考過兩者之間的關係。Spring Aware接口家族一文中我曾詳細闡釋過如何獲取當前運行環境中的BeanFactory、ApplicationContext,咱們不妨在代碼中找尋答案。java
package com.spring.container;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.spring.container")
public class ContainerConfig {
}
複製代碼
package com.spring.container;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/** * @Author: Raphael */
@Component
public class SpringIoc implements BeanFactoryAware, ApplicationContextAware {
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.err.println(System.identityHashCode(beanFactory));
System.out.println(beanFactory.getClass().getName());
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.err.println(System.identityHashCode(applicationContext));
System.out.println(applicationContext.getClass().getName());
}
}
複製代碼
package com.spring.container;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/** * @Author: Raphael */
public class MainContainer {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(ContainerConfig.class);
context.close();
}
}
複製代碼
敏銳的人其實已經發現了矛盾,認知中Spring的根容器應該有且只有一個才合理。可是這分明就是兩個沒有什麼關聯的對象啊。Spring官方文檔如此論述兩者的關係:面試
簡而言之,BeanFactory提供了配置框架和基本功能,ApplicationContext增長了更多針對企業的功能。ApplicationContext是BeanFactory的一個完整的超集。spring
按照官方的解釋:兩者是一個包含與被包含的關係,那麼在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 */
@Component
public 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));
}
}
複製代碼
驗證結果徹底支持官方說明。app
官方對他如此定義:框架
Spring的{@link ConfigurableListableBeanFactory},{@link BeanDefinitionRegistry}的默認實現
成熟的bean工廠
基於bean定義元數據,可經過後處理器進行擴展ide
臺前光亮的是BeanFactory,負重前行的倒是DefaultListableBeanFactory,明明是三我的的電影,我卻始終不能有姓名。那麼DefaultListableBeanFactory的對象是什麼時候產生的呢?一個新的問題又縈繞在個人心頭。答案其實與IOC容器的初始化密不可分,我在這裏不詳敘了。咱們只簡單的剖析一下DefaultListableBeanFactory產生對象的心路歷程。
咱們在MainContainer中調用了以下構造方法:post
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses);
refresh();
}
複製代碼
由於AnnotationConfigApplicationContext繼承了GenericApplicationContext,因此父類的的構造方法也會同時調用,容器對象就在此時誕生。ui
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> T getBean(String name, Class<T> requiredType) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name, requiredType);
}
複製代碼
這裏實際上他並無對此方法有詳細的實現,而是經過getBeanFactory()獲取自身內部的容器對象,而後交由ta實現。 如今脈絡應該足夠清晰了。Spring源碼是設計模式的集大成者,這裏其實運用的就是組合模式。
其實官方有他們兩者的總結
org.springframework.beans和org.springframework.context包是Spring框架的IoC容器的基礎。BeanFactory 接口提供了一種高級配置機制,可以管理任何類型的對象。 ApplicationContext 是其子接口。
增長了如下特性:
Spring官方文檔,真的不許備去看看嘛?
最後: 花長好,月長圓,人長壽