目錄
一、前言
二、Spring IoC容器的設(shè)計
2.1,IoC容器的設(shè)計線路
2.2、應(yīng)用上下文設(shè)計路線
三、IoC容器的具體實現(xiàn)類 DefaultListableBeanFactory(重點)
3.1,作為IoC容器的基礎(chǔ)設(shè)計路線
3.2、作為IoC容器的高級設(shè)計路線
3.3、DefaultListableBeanFactory幾個重要的父類和接口
3.3.1, AbstractBeanFactory 抽象類
3.3.2, AbstractAutowireCapableBeanFactory 抽象類
3.3.3, DefaultSingletonBeanRegistry 讓IoC容器擁有作為“容器”的能力
3.3.4, DefaultListableBeanFactory (重點)
3.3.5, BeanDefinition
四、SpringBoot web工程中的上下文 AnnotationConfigServletWebServerApplicationContext
五、IoC容器的初始化過程
六、IoC容器的依賴注入
一、前言
寫這篇博文的主要目的如下:
- 通過相關(guān)類和接口分析IoC容器到底長什么樣。
- 闡述筆者對Spring上下文和容器的理解。
- 介紹重要的類輔助理解SpringBoot的啟動流程。
二、Spring IoC容器的設(shè)計
看看下面這張圖(摘自《Spring技術(shù)內(nèi)幕》),IoC容器的設(shè)計分為兩條線,
- BeanFactory ==> HierarchicalBeanFactory ==>ConfigurableBeanFactory ,這條線可以理解成IoC容器的設(shè)計路線。
- BeanFactory ==> ListableBeanFactory ==> ApplicationContext ==> ConfigurableApplicationContext ,這條可以成為Spring應(yīng)用上下文的設(shè)計路線。
為什么這樣要分兩條線呢,主要是將容器和上下文區(qū)分開來。因為在在Spring項目中,上下文對容器不僅是擴(kuò)展的關(guān)系,更重要的是持有的關(guān)系,上下文是以屬性的形式持有了容器,開發(fā)者可以通過上下文對象獲取到容器。筆者十分傾向于將二者分開來理解。當(dāng)然也可以將應(yīng)用上下文理解成容器的高級表現(xiàn)形式。

2.1,IoC容器的設(shè)計線路
BeanFactory定義了IoC容器的基本規(guī)范,包括getBean()按類型和按名稱的獲取Bean的方法。


HierarchicalBeanFactory 在BeanFactory的基礎(chǔ)上增加了getParentBeanFactory()方法,使BeanFactory具備了雙親IoC容器管理的功能。
ConfigurableBeanFactory接口提供了配置BeanFactory的各種方法。比如setParentBeanFactory()方法,配置上面提到的雙親IoC容器,addBeanPostProcessor()方法,配置Bean后置處理器等。
到這里先埋個包袱:到ConfigurableBeanFactory接口為止,IoC容器還沒有具備作為“容器”最基本的功能,那就是能裝東西。
2.2、應(yīng)用上下文設(shè)計路線
上面說了應(yīng)用上下文是IoC容器的高級表現(xiàn)形式,ListableBeanFactory具備了操作BeanDefinition 的能力,比如getBeanDefinitionCount()方法,可以獲取Bean的總數(shù)等。
ApplicationContext 類那就厲害了,如下代碼所示,實現(xiàn)了一大堆接口
public interface ApplicationContext extends
EnvironmentCapable,
ListableBeanFactory,
HierarchicalBeanFactory,
MessageSource,
ApplicationEventPublisher,
ResourcePatternResolver
- MessageSource,支持不同的信息源。具備支持國際化的實現(xiàn),為開發(fā)多語言版本的應(yīng)用提供服務(wù)。
- ResourcePatternResolver,訪問數(shù)據(jù)源。具備了從不同地方得到Bean定義資源的能力,比如:xml,java config,注解等等。
- ApplicationEventPublisher,發(fā)布事件。使應(yīng)用上下文具備了事件機(jī)制。事件機(jī)制為Bean聲明周期的管理提供了便利。
WebApplicationContext擴(kuò)展了對web應(yīng)用的支持。
ConfigurableApplicationContext就更重要了,看過Spring源碼的都知道一個重要的方法叫refresh,沒錯就是在這個接口中定義的。最重要的是擴(kuò)展了配置上下文的功能,和控制上下文生命周期的能力等等。

三、IoC容器的具體實現(xiàn)類 DefaultListableBeanFactory(重點)
首先證明一點,為什么說DefaultListableBeanFactory類是具體的實現(xiàn)類呢?
隨便啟動一個SpringBoot項目找到第25行代碼(在SpringBoot的啟動流程系列博文中有介紹)
public ConfigurableApplicationContext run(String... args) {
//記錄程序運(yùn)行時間
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// ConfigurableApplicationContext Spring 的上下文
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//從META-INF/spring.factories中獲取監(jiān)聽器
//1、獲取并啟動監(jiān)聽器
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//2、構(gòu)造容器環(huán)境
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
//處理需要忽略的Bean
configureIgnoreBeanInfo(environment);
//打印banner
Banner printedBanner = printBanner(environment);
///3、初始化容器
context = createApplicationContext();
//實例化SpringBootExceptionReporter.class,用來支持報告關(guān)于啟動的錯誤
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[]{ConfigurableApplicationContext.class}, context);
//4、刷新容器前的準(zhǔn)備階段
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//5、刷新容器
refreshContext(context);
//刷新容器后的擴(kuò)展接口
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
} catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
} catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
debug

如2標(biāo)注點所示IoC容器的真實面孔就是這個DefaultListableBeanFactory類了。當(dāng)然他還有一個子類XmlBeanFactory,不過都已經(jīng)被標(biāo)注為棄用了(@Deprecated)在《Spring技術(shù)內(nèi)幕》這本書里面也是著重的講的這個類,可能當(dāng)時作者是以SpringMVC項目來講解的吧。XmlBeanFactory顧名思義就是提供了對xml配置方式的支持。呃。。。又勾起了用SpringMVC的痛苦回憶。

言歸正傳,
如下圖,看看他的繼承關(guān)系

章節(jié)二中提到了很多的IoC容器系列,這樣總結(jié)一下吧,俗話說一流企業(yè)做標(biāo)準(zhǔn),二流企業(yè)做產(chǎn)品,章節(jié)二中的那一坨就是IoC容器的實現(xiàn)標(biāo)準(zhǔn),本章節(jié)我們要總結(jié)的類DefaultListableBeanFactory就是IoC容器的具體產(chǎn)品。
看見上圖中那一堆接口和類是不是有點懵,沒關(guān)系,咱們慢慢梳理一下。
3.1,作為IoC容器的基礎(chǔ)設(shè)計路線

這條線路在上一章節(jié)中已經(jīng)梳理過了。只是多出了ConfigurableListableBeanFactory接口,ConfigurableListableBeanFactory接口主要是增加指定忽略類型和接口等

3.2、作為IoC容器的高級設(shè)計路線

這條設(shè)計路線乍一看還是挺復(fù)雜的,的確是這樣。
1, BeanFactory ==> AutowireCapableBeanFactory ==> AbstractAutowireCapableBeanFactory ==> DefaultListableBeanFactory
在這條線路中,AutowireCapableBeanFactory接口定義了自動注入bean(autowireBean()),創(chuàng)建bean(createBean()),初始化bean(initializeBean())方法等。那么真正實現(xiàn)這些方法的類便是AbstractAutowireCapableBeanFactory。
AbstractAutowireCapableBeanFactory抽象類中實現(xiàn)了AutowireCapableBeanFactory接口定義的方法。在此基礎(chǔ)上通過繼承AbstractBeanFactory具備了操作Bean的能力。
2, SingletonBeanRegistry ==> DefaultSingletonBeanRegistry ==> FactoryBeanRegistrySupport ==> AbstractBeanFactory ==> AutowireCapableBeanFactory ==> DefaultListableBeanFactory
這條關(guān)系鏈有點長,在這條鏈中我們要關(guān)心的是SingletonBeanRegistry接口,顧名思義,這個接口是單例Bean的注冊接口。當(dāng)然也不止注冊這么簡單。如下圖中所示,除了注冊單例之外,還定義獲取單例的方法。
注意:為什么只有singleton的注冊中心,而沒有prototype類型的Bean的注冊中心呢?因為單例Bean(singleton)是Spring幫我們創(chuàng)建的并維護(hù)的,原型Bean(prototype)是每次獲取都會創(chuàng)建出來一個實例。本質(zhì)是不同的。

3, AliasRegistry ==> SimpleAliasRegistry ==> DefaultSingletonBeanRegistry ==> FactoryBeanRegistrySupport ==> AbstractBeanFactory ==> AutowireCapableBeanFactory ==> DefaultListableBeanFactory
這條路線呢,主要是提供管理別稱的能力。因為不是重點,在此就不詳細(xì)分析了。
4, AliasRegistry ==> BeanDefinitionRegistry ==> DefaultListableBeanFactory
BeanDefinitionRegistry接口要重點說一下,該接口是BeanDefinition的注冊中心。使DefaultListableBeanFactory具備操作BeanDefinition的能力。看一下它有什么方法。

包括了注冊,刪除,獲取BeanDefinition的方法。當(dāng)然這只是個接口,這些方法的具體實現(xiàn)在DefaultListableBeanFactory中。
3.3、DefaultListableBeanFactory幾個重要的父類和接口
3.3.1, AbstractBeanFactory 抽象類

如上圖所示,AbstractBeanFactory中實現(xiàn)了BeanFactory中定義的幾個重要的方法。常用的注解 @Autowired @Resource(name = "xxx") 大家都知道一個是按類查找,一個是按名獲取。具體實現(xiàn)這兩個注解的方法就是上圖中圈出來的幾個方法。幾個getBean()方法最終都進(jìn)入了doGetBean()方法。doGetBean()方法是實際獲得Bean的地方,也是觸發(fā)依賴注入發(fā)生的地方。在SpringBoot啟動流程總會對這個方法進(jìn)行詳細(xì)的介紹。
3.3.2, AbstractAutowireCapableBeanFactory 抽象類
AbstractBeanFactory中實現(xiàn)了getBean()方法,AbstractAutowireCapableBeanFactory中實現(xiàn)了Bean的創(chuàng)建方法。
當(dāng)我們需要定義一個Bean通常會有這樣寫 @Bean(name = "test", initMethod = "init", destroyMethod = "destroy") 。AbstractAutowireCapableBeanFactory中完成了一個Bean從 create(createBean()) ==> createInstance(createBeanInstance()) ==> init(invokeInitMethods()) 的所有工作。所以這個抽象類的作用不言而喻。具體的創(chuàng)建過程,會在SpringBoot的啟動流程中詳細(xì)介紹。
3.3.3, DefaultSingletonBeanRegistry 讓IoC容器擁有作為“容器”的能力
其實我們經(jīng)常說的Spring 容器,這個容器其實更多的是BeanFactory所代表的意義:Bean生產(chǎn)工廠。是滴,通常我們理解的容器應(yīng)該是能裝東西的,但是spring 容器不是代表代表水桶一樣的東西,而是像富士康一樣,生產(chǎn)東西的地方。比如我們需要一個Bean,我們只需要告訴spring,spring就會給我們。所以到目前為止我們還沒有看到IoC作為“容器”的能力。以上言論純屬自己理解,不喜勿噴。
DefaultSingletonBeanRegistry屬性先貼出來
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
/**
* Cache of singleton objects: bean name --> bean instance
* 緩存 單例對象
*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);//好習(xí)慣,創(chuàng)建ConcurrentHashMap,指定初始化因子,縱觀Spring源碼,創(chuàng)建HashMap,都有初始化因子。get
/**
* Cache of singleton factories: bean name --> ObjectFactory
* 緩存 單例工廠
*/
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/**
* Cache of early singleton objects: bean name --> bean instance
* 緩存 提前暴露的對象
*/
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/**
* Set of registered singletons, containing the bean names in registration order
* 已經(jīng)注冊的單例對象集合,按照注冊順序排序的,并且是不可重復(fù)的。
*/
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
/**
* Names of beans that are currently in creation
*
*/
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
/**
* Names of beans currently excluded from in creation checks
*/
private final Set<String> inCreationCheckExclusions =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
/**
* List of suppressed Exceptions, available for associating related causes
*/
@Nullable
private Set<Exception> suppressedExceptions;
/**
* Flag that indicates whether we're currently within destroySingletons
*/
private boolean singletonsCurrentlyInDestruction = false;
/**
* Disposable bean instances: bean name --> disposable instance
* spring是作為一個注冊中心的樣子,在容器shutdown的時候,直接從這里面找到需要執(zhí)行destory鉤子的Bean
*/
private final Map<String, Object> disposableBeans = new LinkedHashMap<>();
/**
* Map between containing bean names: bean name --> Set of bean names that the bean contains
* 名稱為name的bean,所持有的beans 的映射關(guān)系
*/
private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<>(16);
/**
* Map between dependent bean names: bean name --> Set of dependent bean names
* 名稱為name的bean與其所依賴的bean的映射關(guān)系
*/
private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);
/**
* Map between depending bean names: bean name --> Set of bean names for the bean's dependencies
*/
private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);
}
屬性singletonObjects ,沒錯,就是這個東東,最終存儲單例(singleton)Bean的地方,在SpringBoot啟動流程中,會詳細(xì)介紹存取的過程。上面說了原型(prototype)Bean是不需要緩存的,不解釋了。到這里我們初步看到了IoC作為“容器”該有的樣子。
DefaultSingletonBeanRegistry上面提到的SingletonBeanRegistry接口的相關(guān)方法,并且增加了很多對單例的操作的方法。
3.3.4, DefaultListableBeanFactory (重點)
上面我們從IoC容器的宏觀設(shè)計角度闡述了DefaultListableBeanFactory作為IoC容器的具體實現(xiàn)的設(shè)計思想。在這里來分析一下這個類本身的設(shè)計。
首先看看該類的屬性
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
/**
* Map from serialized id to factory instance
* 緩存 序列化ID到 DefaultListableBeanFactory 實例的映射
*/
private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories =
new ConcurrentHashMap<>(8);
/**
* Optional id for this factory, for serialization purposes
*/
@Nullable
private String serializationId;
/**
* Whether to allow re-registration of a different definition with the same name
*/
private boolean allowBeanDefinitionOverriding = true;
/**
* Whether to allow eager class loading even for lazy-init beans
*/
private boolean allowEagerClassLoading = true;
/**
* Optional OrderComparator for dependency Lists and arrays
*/
@Nullable
private Comparator<Object> dependencyComparator;
/**
* Resolver to use for checking if a bean definition is an autowire candidate
* 被用來解決去校驗一個BeanDefinition是不是自動裝載的候選人
*/
private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();
/**
* Map from dependency type to corresponding autowired value
* 緩存 類型對應(yīng)的自動裝載的Bean
*/
private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16);
/**
* Map of bean definition objects, keyed by bean name
* 緩存 beanName到BeanDefinition的映射關(guān)系
*/
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
/**
* Map of singleton and non-singleton bean names, keyed by dependency type
* 緩存 類型 和 beanName的映射關(guān)系
*/
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);
/**
* Map of singleton-only bean names, keyed by dependency type
* 緩存 類型 和 單例Bean names的映射
*/
private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64);
/**
* List of bean definition names, in registration order
* 緩存 beanDefinition name的list
*/
private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
/**
* List of names of manually registered singletons, in registration order
*/
private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16);
/**
* Cached array of bean definition names in case of frozen configuration
*/
@Nullable
private volatile String[] frozenBeanDefinitionNames;
/**
* Whether bean definition metadata may be cached for all beans
*/
private volatile boolean configurationFrozen = false;
}
在Spring中,實際上是把DefaultListableBeanFactory作為一個默認(rèn)的功能完整的IoC容器來使用。 DefaultListableBeanFactory作為一個功能完整的容器具備了除以上父類所具有功能外,還加入了對BeanDefinition的管理和維護(hù)。從上面的代碼可以看到一個重要的屬性:beanDefinitionMap。beanDefinitionMap緩存了Bean name到 BeanDefinition的映射。到這里是不是發(fā)現(xiàn)了IoC容器另外一個作為“容器”的能力。
在我的理解范圍內(nèi),IoC容器作為“容器”真正裝的兩個最總要的能力算是總結(jié)完了,一個是裝單例(Singleton)Bean,一個是裝BeanDefinition。
3.3.5, BeanDefinition
Spring通過定義BeanDefinition來管理基于Spring的應(yīng)用中的各種對象以及他們之間的相互依賴關(guān)系。BeanDefinition抽象了我們對Bean的定義,是讓容器起作用的主要數(shù)據(jù)類型。我么都知道在計算機(jī)世界里,所有的功能都是建立在通過數(shù)據(jù)對現(xiàn)實進(jìn)行抽象的基礎(chǔ)上的。IoC容器是用來管理對象依賴關(guān)系的,對IoC容器來說,BeanDefinition就是對依賴反轉(zhuǎn)模式中管理的對象依賴關(guān)系的數(shù)據(jù)抽象,也是容器實現(xiàn)依賴反轉(zhuǎn)功能的核心數(shù)據(jù)結(jié)構(gòu),依賴反轉(zhuǎn)功能都是圍繞對這個BeanDefinition的處理來完成的。這些BeanDefinition就像是容器里裝的水,有了這些基本數(shù)據(jù),容器才能發(fā)揮作用。簡單一句話來說,BeanDefinition就是Bean的元數(shù)據(jù),BeanDefinition存放了對Bean的基本描述,包括Bean擁有什么屬性,方法,Bean的位置等等Bean的各種信息。IoC容器可以通過BeanDefinition生成Bean。
BeanDefinition究竟長什么樣呢?
在同第三章debug的地方一樣,點開beanFactory,然后查看beanDefinitionMap屬性。

OK,BeanDefinition就是長這樣了。具體怎么通過它生成Bean,在SpringBoot啟動流程中會詳細(xì)介紹。
四、SpringBoot web工程中的上下文 AnnotationConfigServletWebServerApplicationContext
在SpringBoot工程中,應(yīng)用類型分為三種,如下代碼所示。
public enum WebApplicationType {
/**
* 應(yīng)用程序不是web應(yīng)用,也不應(yīng)該用web服務(wù)器去啟動
*/
NONE,
/**
* 應(yīng)用程序應(yīng)作為基于servlet的web應(yīng)用程序運(yùn)行,并應(yīng)啟動嵌入式servlet web(tomcat)服務(wù)器。
*/
SERVLET,
/**
* 應(yīng)用程序應(yīng)作為 reactive web應(yīng)用程序運(yùn)行,并應(yīng)啟動嵌入式 reactive web服務(wù)器。
*/
REACTIVE
}
對應(yīng)三種應(yīng)用類型,SpringBoot項目有三種對應(yīng)的應(yīng)用上下文,我們以web工程為例,即其上下文為AnnotationConfigServletWebServerApplicationContext
public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework.boot."
+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";
public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
+ "annotation.AnnotationConfigApplicationContext";
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
} catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass",
ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
我們先看一下AnnotationConfigServletWebServerApplicationContext的設(shè)計。 
在2.2中已經(jīng)介紹了ApplicationContext的設(shè)計
關(guān)于AnnotationConfigServletWebServerApplicationContext詳細(xì)的設(shè)計路線在這里就不像DefaultListableBeanFactory容器那么詳細(xì)的去講解了。在第二章說過,應(yīng)用上下文可以理解成IoC容器的高級表現(xiàn)形式,拿上圖和DefaultListableBeanFactory的繼承關(guān)系圖,不難發(fā)現(xiàn),應(yīng)用上下文確實是在IoC容器的基礎(chǔ)上豐富了一些高級功能。在第二章中,我們還說過應(yīng)用上下文對IoC容器是持有的關(guān)系。繼續(xù)看第二章debug的截圖,context就是AnnotationConfigServletWebServerApplicationContext的神秘面孔,他的一個屬性beanFactory就是IoC容器(DefaultListableBeanFactory)。所以他們之間是持有,和擴(kuò)展的關(guān)系。
接下來看GenericApplicationContext類
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
private final DefaultListableBeanFactory beanFactory;
...
}
第一行赫然定義了beanFactory屬性,正是DefaultListableBeanFactory對象。
關(guān)于上下文還有另外一個最重要的方法refresh,上文中說道該方法是在ConfigurableApplicationContext接口中定義的,那么在哪實現(xiàn)的該方法呢?
看AbstractApplicationContext類。
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//刷新上下文環(huán)境
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//這里是在子類中啟動 refreshBeanFactory() 的地方
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//準(zhǔn)備bean工廠,以便在此上下文中使用
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//設(shè)置 beanFactory 的后置處理
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//調(diào)用 BeanFactory 的后處理器,這些處理器是在Bean 定義中向容器注冊的
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
//注冊Bean的后處理器,在Bean創(chuàng)建過程中調(diào)用
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
//對上下文中的消息源進(jìn)行初始化
initMessageSource();
// Initialize event multicaster for this context.
//初始化上下文中的事件機(jī)制
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//初始化其他特殊的Bean
onRefresh();
// Check for listener beans and register them.
//檢查監(jiān)聽Bean并且將這些監(jiān)聽Bean向容器注冊
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//實例化所有的(non-lazy-init)單件
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
//發(fā)布容器事件,結(jié)束Refresh過程
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
} finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
OK,應(yīng)用上下文就介紹到這里。
五、IoC容器的初始化過程
在這里我們先口述一下IoC容器的初始化過程吧,源碼分析,請移步SpringBoot啟動流程分析。
簡單來說IoC容器的初始化過程是由前面介紹的refresh()方法啟動的,這個方法標(biāo)志著IoC容器的正式啟動。具體來說,這個啟動包括三個過程
1 BeanDefinition的Resource定位
2 BeanDefinition的載入
3 向IoC容器注冊BeanDefinition
1、第一個過程:Resource定位
這個定位指的是BeanDefinition的資源定位,它由ResourceLoader通過統(tǒng)一的Resource接口完成,這個Resource對各種形式的BeanDefinition的使用都提供了統(tǒng)一接口。對于這些BeanDefinition的存在形式,可以是通過像SpringMVC中的xml定義的Bean,也可以是像在類路徑中的Bean定義信息,比如使用@Component等注解定義的。這個過程類似于容器尋找數(shù)據(jù)的過程,就像用水桶裝水先要把水找到一樣。
結(jié)合SpringBoot說一下這個過程,對于SpringBoot,我們都知道他的包掃描是從主類所在的包開始掃描的,那這個定位的過程在SpringBoot中具體是這樣的,在refresh容器之前(prepareContext()方法中),會先將主類解析成BeanDefinition,然后在refresh方法中并且是掃描Bean之前,解析主類的BeanDefinition獲取basePackage的路徑。這樣就完成了定位的過程。(先不討論SpringBoot中指定掃描包路徑和自動裝配)
2、第二個過程:BeanDefinition的載入
這個載入過程是把用戶定義好的Bean表示成IoC容器內(nèi)部的數(shù)據(jù)結(jié)構(gòu),而這個容器內(nèi)部的數(shù)據(jù)結(jié)構(gòu)就是BeanDefinition。
在SpringBoot中,上面我們說到通過主類找到了basePackage,SpringBoot會將該路徑拼接成:classpath:org/springframework/boot/demo//.class這樣的形式,然后一個叫做PathMatchingResourcePatternResolver的類會將該路徑下所有的.class文件都加載進(jìn)來,然后遍歷判斷是不是有@Component注解,如果有的話,就是我們要裝載的BeanDefinition。大致過程就是這樣的了。
注意:@Configuration,@Controller,@Service等注解底層都是@Component注解,只不過包裝了一層罷了。
3、第三個過程:注冊BeanDefinition
這個過程通過調(diào)用上文提到的BeanDefinitionRegister接口的實現(xiàn)來完成。這個注冊過程把載入過程中解析得到的BeanDefinition向IoC容器進(jìn)行注冊。通過上文的分析,我們可以看到,在IoC容器中將BeanDefinition注入到一個ConcurrentHashMap中,IoC容器就是通過這個HashMap來持有這些BeanDefinition數(shù)據(jù)的。比如DefaultListableBeanFactory 中的beanDefinitionMap屬性。
六、IoC容器的依賴注入
上面對IoC容器的初始化過程進(jìn)行了詳細(xì)的介紹,這個過程完成的主要的工作是在IoC容器中建立BeanDefinition數(shù)據(jù)映射。在此過程中并沒有看到IoC容器對Bean的依賴關(guān)系進(jìn)行注入。依賴注入是Spring實現(xiàn)“控制反轉(zhuǎn)”的重要一環(huán)。Spring將依賴關(guān)系交給IoC容器來完成。
依賴控制反轉(zhuǎn)的實現(xiàn)有很多種方式。在Spring中,IoC容器是實現(xiàn)這個模式的載體,它可以在對象生成或者初始化時直接將數(shù)據(jù)注入到對象中,也可以通過將對象注入到對象數(shù)據(jù)域中的方式來注入對方法調(diào)用的依賴。這種依賴注入是可以遞歸的,對象被逐層注入。