接上文 啃啃老菜: Spring IOC核心源碼學習(一) ,本文將以 ClassPathXmlApplicationContext 這個容器的實現作為基礎,學習容器的初始化過程。
ClassPathXmlApplicationContext 類體系結構
以下是 ClassPathXmlApplicationContext 的類繼承體系結構,理解這個結構有助于后面的代碼理解。

左邊黃色部分是 ApplicationContext 體系繼承結構,右邊是 BeanFactory 的結構體系,兩個結構是典型模板方法設計模式的使用。
從該繼承體系可以看出:
1. BeanFactory 是一個 bean 工廠的最基本定義,里面包含了一個 bean 工廠的幾個最基本的方法,getBean(…) 、 containsBean(…) 等 ,是一個很純粹的bean工廠,不關注資源、資源位置、事件等。ApplicationContext 是一個容器的最基本接口定義,它繼承了 BeanFactory, 擁有工廠的基本方法。同時繼承了ApplicationEventPublisher 、 MessageSource 、 ResourcePatternResolver 等接口,使其 定義了一些額外的功能,如資源、事件等這些額外的功能。
2. AbstractBeanFactory 和 AbstractAutowireCapableBeanFactory 是兩個模板抽象工廠類。AbstractBeanFactory 提供了 bean 工廠的抽象基類,同時提供了 ConfigurableBeanFactory 的完整實現。AbstractAutowireCapableBeanFactory 是繼承了 AbstractBeanFactory 的抽象工廠,里面提供了 bean 創建的支持,包括 bean 的創建、依賴注入、檢查等等功能,是一個核心的 bean 工廠基類。
3. ClassPathXmlApplicationContext之 所以擁有 bean 工廠的功能是通過持有一個真正的 bean 工廠DefaultListableBeanFactory 的實例,并通過 代理 該工廠完成。
4. ClassPathXmlApplicationContext 的初始化過程是對本身容器的初始化同時也是對其持有的DefaultListableBeanFactory 的初始化。
下面通過源碼著重介紹一個容器的初始化過程,并重點理解 bean 的創建過程。
容器初始化過程
通過上文 啃啃老菜: Spring IOC核心源碼學習(一) 已經可以了解一個容器的大概過程是:

整個過程可以理解為是容器的初始化過程。第一個過程是 ApplicationContext 的職責范圍,第二步是 BeanFactory的職責范圍??梢钥闯?nbsp;ApplicationContext 是一個運行時的容器需要提供不容資源環境的支持,屏蔽不同環境的差異化。而 BeanDifinition 是內部關于 bean 定義的基本結構。 Bean 的創建就是基于它,回頭會介紹一下改結構的定義。下面看一下整個容器的初始化過程。
容器的初始化是通過調用 refresh() 來實現。該方法是非常重要的一個方法,定義在 AbstractApplicationContext接口里。 AbstractApplicationContext 是容器的最基礎的一個抽象父類。也就是說在該里面定義了一個容器初始化的基本流程,流程里的各個方法有些有提供了具體實現,有些是抽象的 ( 因為不同的容器實例不一樣 ) ,由繼承它的每一個具體容器完成定制??纯?nbsp;refresh 的基本流程:
- public void refresh() throws BeansException, IllegalStateException {
- synchronized (this.startupShutdownMonitor) {
- // Prepare this context for refreshing.
- prepareRefresh();
- // Tell the subclass to refresh the internal bean factory.
- ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
- // Prepare the bean factory for use in this context.
- prepareBeanFactory(beanFactory);
- try {
- // Allows post-processing of the bean factory in context subclasses.
- postProcessBeanFactory(beanFactory);
- // Invoke factory processors registered as beans in the context.
- invokeBeanFactoryPostProcessors(beanFactory);
- // Register bean processors that intercept bean creation.
- registerBeanPostProcessors(beanFactory);
- // Initialize message source for this context.
- initMessageSource();
- // Initialize event multicaster for this context.
- initApplicationEventMulticaster();
- // Initialize other special beans in specific context subclasses.
- onRefresh();
- // Check for listener beans and register them.
- registerListeners();
- // Instantiate all remaining (non-lazy-init) singletons.
- finishBeanFactoryInitialization(beanFactory);
- // Last step: publish corresponding event.
- finishRefresh();
- }
- catch (BeansException ex) {
- // Destroy already created singletons to avoid dangling resources.
- beanFactory.destroySingletons();
- // Reset 'active' flag.
- cancelRefresh(ex);
- // Propagate exception to caller.
- throw ex;
- }
- }
- }
解釋如下:

Bean 的創建過程
Bean的創建過程基本是BeanFactory所要完成的事情.
根據以上過程,將會重點帶著以下兩個個問題來理解核心代碼:
1.Bean 的創建時機
bean 是在什么時候被創建的,有哪些規則。
2.Bean 的創建過程
bean 是怎么創建的,會選擇哪個構造函數?依賴如何注入? InitializingBean 的 set 方法什么時候被調用?實現ApplicationContextAware, BeanFactoryAware,BeanNameAware, ResourceLoaderAware 這些接口的 bean 的set 方法何時被調用?
在解釋這兩個問題前,先看一下 BeanDefinition 接口的定義。

從該接口定義可以看出,通過 bean 定義能夠得到 bean 的詳細信息,如類名子、工廠類名稱、 scope 、是否單例、是否抽象、是否延遲加載等等。基于此,來看一下以下兩個問題:
問題 1 : Bean 的創建時機
bean 是在什么時候被創建的,有哪些規則?
容器初始化的時候會預先對單例和非延遲加載的對象進行預先初始化。其他的都是延遲加載是在第一次調用getBean 的時候被創建。從 DefaultListableBeanFactory 的 preInstantiateSingletons 里可以看到這個規則的實現。
- public void preInstantiateSingletons() throws BeansException {
- if (this.logger.isInfoEnabled()) {
- this.logger.info("Pre-instantiating singletons in " + this);
- }
-
- synchronized (this.beanDefinitionMap) {
- for (Iterator it = this.beanDefinitionNames.iterator(); it.hasNext();) {
- String beanName = (String) it.next();
- RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
- <span style="color: #ff0000;">if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {</span>
-
-
-
- //對非抽象、單例的和非延遲加載的對象進行實例化。
- if (isFactoryBean(beanName)) {
- FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
- if (factory instanceof SmartFactoryBean && ((SmartFactoryBean) factory).isEagerInit()) {
- getBean(beanName);
- }
- }
- else {
- getBean(beanName);
- }
- }
- }
- }
- }
從上面來看對于以下配置,只有 singletonBean 會被預先創建。
- <?xml version="1.0" encoding="GB2312"?>
- <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
- <beans default-autowire="byName">
- <bean id="otherBean" class="com.test.OtherBean" scope="prototype"/>
- <bean id="myBean" class="com.test.MyBean" lazy-init="true"/>
- <bean id="singletonBean" class="com.test.SingletonBean"/>
- </beans>
問題二:Bean 的創建過程
對于 bean 的創建過程其實都是通過調用工廠的 getBean 方法來完成的。這里面將會完成對構造函數的選擇、依賴注入等。
無論預先創建還是延遲加載都是調用getBean實現,AbstractBeanFactory 定義了 getBean 的過程:
- protected Object doGetBean(
- final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {
- final String beanName = transformedBeanName(name);
- Object bean = null;
- // Eagerly check singleton cache for manually registered singletons.
- Object sharedInstance = getSingleton(beanName);
- if (sharedInstance != null && args == null) {
- if (logger.isDebugEnabled()) {
- if (isSingletonCurrentlyInCreation(beanName)) {
- logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
- "' that is not fully initialized yet - a consequence of a circular reference");
- }
- else {
- logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
- }
- }
- bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
- }
- else {
- // Fail if we're already creating this bean instance:
- // We're assumably within a circular reference.
- if (isPrototypeCurrentlyInCreation(beanName)) {
- throw new BeanCurrentlyInCreationException(beanName);
- }
-
- // Check if bean definition exists in this factory.
- BeanFactory parentBeanFactory = getParentBeanFactory();
- if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
- // Not found -> check parent.
- String nameToLookup = originalBeanName(name);
- if (args != null) {
- // Delegation to parent with explicit args.
- return parentBeanFactory.getBean(nameToLookup, args);
- }
- else {
- // No args -> delegate to standard getBean method.
- return parentBeanFactory.getBean(nameToLookup, requiredType);
- }
- }
-
- if (!typeCheckOnly) {
- markBeanAsCreated(beanName);
- }
-
- final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
- checkMergedBeanDefinition(mbd, beanName, args);
-
- // Guarantee initialization of beans that the current bean depends on.
- String[] dependsOn = mbd.getDependsOn();
- if (dependsOn != null) {
- for (int i = 0; i < dependsOn.length; i++) {
- String dependsOnBean = dependsOn[i];
- getBean(dependsOnBean);
- registerDependentBean(dependsOnBean, beanName);
- }
- }
- // Create bean instance.
- <span style="color: #ff0000;">if (mbd.isSingleton()) {//單例對象創建過程,間接通過getSingleton方法來創建,里面會實現將單例對象緩存</span>
-
-
-
-
- sharedInstance = getSingleton(beanName, new ObjectFactory() {
- public Object getObject() throws BeansException {
- try {
- return createBean(beanName, mbd, args);
- }
- catch (BeansException ex) {
- // Explicitly remove instance from singleton cache: It might have been put there
- // eagerly by the creation process, to allow for circular reference resolution.
- // Also remove any beans that received a temporary reference to the bean.
- destroySingleton(beanName);
- throw ex;
- }
- }
- });
- bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
- }
-
- <span style="color: #ff0000;">else if (mbd.isPrototype()) {//非單例對象創建</span>
-
-
-
-
- // It's a prototype -> create a new instance.
- Object prototypeInstance = null;
- try {
- beforePrototypeCreation(beanName);
- prototypeInstance = createBean(beanName, mbd, args);<span style="color: #ff0000;">//直接調用createBean</span>
-
-
-
-
- }
- finally {
- afterPrototypeCreation(beanName);
- }
- bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
- }
-
- else {
- String scopeName = mbd.getScope();
- final Scope scope = (Scope) this.scopes.get(scopeName);
- if (scope == null) {
- throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
- }
- try {
- Object scopedInstance = scope.get(beanName, new ObjectFactory() {
- public Object getObject() throws BeansException {
- beforePrototypeCreation(beanName);
- try {
- return createBean(beanName, mbd, args);
- }
- finally {
- afterPrototypeCreation(beanName);
- }
- }
- });
- bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
- }
- catch (IllegalStateException ex) {
- throw new BeanCreationException(beanName,
- "Scope '" + scopeName + "' is not active for the current thread; " +
- "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
- ex);
- }
- }
- }
- // Check if required type matches the type of the actual bean instance.
- if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
- throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
- }
- return bean;
- }
GetBean 的大概過程:
1. 先試著從單例緩存對象里獲取。
2. 從父容器里取定義,有則由父容器創建。
3. 如果是單例,則走單例對象的創建過程:在 spring 容器里單例對象和非單例對象的創建過程是一樣的。都會調用父類 AbstractAutowireCapableBeanFactory 的 createBean 方法。 不同的是單例對象只創建一次并且需要緩存起來。 DefaultListableBeanFactory 的父類 DefaultSingletonBeanRegistry 提供了對單例對象緩存等支持工作。所以是單例對象的話會調用 DefaultSingletonBeanRegistry 的 getSingleton 方法,它會間接調用AbstractAutowireCapableBeanFactory 的 createBean 方法。
如果是 Prototype 多例則直接調用父類 AbstractAutowireCapableBeanFactory 的 createBean 方法。
bean的創建是由AbstractAutowireCapableBeanFactory來定義:
- protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
- throws BeanCreationException {
- AccessControlContext acc = AccessController.getContext();
- return AccessController.doPrivileged(new PrivilegedAction() {
- public Object run() {
- if (logger.isDebugEnabled()) {
- logger.debug("Creating instance of bean '" + beanName + "'");
- }
- // Make sure bean class is actually resolved at this point.
- resolveBeanClass(mbd, beanName);
- // Prepare method overrides.
- try {
- mbd.prepareMethodOverrides();
- }
- catch (BeanDefinitionValidationException ex) {
- throw new BeanDefinitionStoreException(mbd.getResourceDescription(),
- beanName, "Validation of method overrides failed", ex);
- }
- try {
- // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
- Object bean = resolveBeforeInstantiation(beanName, mbd);
- if (bean != null) {
- return bean;
- }
- }
- catch (Throwable ex) {
- throw new BeanCreationException(mbd.getResourceDescription(), beanName,
- "BeanPostProcessor before instantiation of bean failed", ex);
- }
- Object beanInstance = doCreateBean(beanName, mbd, args);
- if (logger.isDebugEnabled()) {
- logger.debug("Finished creating instance of bean '" + beanName + "'");
- }
- return beanInstance;
- }
- }, acc);
- }
createBean 會調用 doCreateBean 方法:
- protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
- // Instantiate the bean.
- BeanWrapper instanceWrapper = null;
- if (mbd.isSingleton()) {
- instanceWrapper = (BeanWrapper) this.factoryBeanInstanceCache.remove(beanName);
- }
- if (instanceWrapper == null) {
- instanceWrapper = createBeanInstance(beanName, mbd, args);
- }
- final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
- Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
-
- // Allow post-processors to modify the merged bean definition.
- synchronized (mbd.postProcessingLock) {
- if (!mbd.postProcessed) {
- applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
- mbd.postProcessed = true;
- }
- }
-
- // Eagerly cache singletons to be able to resolve circular references
- // even when triggered by lifecycle interfaces like BeanFactoryAware.
- boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
- isSingletonCurrentlyInCreation(beanName));
- if (earlySingletonExposure) {
- if (logger.isDebugEnabled()) {
- logger.debug("Eagerly caching bean '" + beanName +
- "' to allow for resolving potential circular references");
- }
- addSingletonFactory(beanName, new ObjectFactory() {
- public Object getObject() throws BeansException {
- return getEarlyBeanReference(beanName, mbd, bean);
- }
- });
- }
- // Initialize the bean instance.
- Object exposedObject = bean;
- try {
- populateBean(beanName, mbd, instanceWrapper);
- exposedObject = initializeBean(beanName, exposedObject, mbd);
- }
- catch (Throwable ex) {
- if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
- throw (BeanCreationException) ex;
- }
- else {
- throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
- }
- }
- if (earlySingletonExposure) {
- Object earlySingletonReference = getSingleton(beanName, false);
- if (earlySingletonReference != null) {
- if (exposedObject == bean) {
- exposedObject = earlySingletonReference;
- }
- else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
- String[] dependentBeans = getDependentBeans(beanName);
- Set actualDependentBeans = new LinkedHashSet(dependentBeans.length);
- for (int i = 0; i < dependentBeans.length; i++) {
- String dependentBean = dependentBeans[i];
- if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean);
- }
- }
- if (!actualDependentBeans.isEmpty()) {
- throw new BeanCurrentlyInCreationException(beanName,
- "Bean with name '" + beanName + "' has been injected into other beans [" +
- StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
- "] in its raw version as part of a circular reference, but has eventually been " +
- "wrapped. This means that said other beans do not use the final version of the " +
- "bean. This is often the result of over-eager type matching - consider using " +
- "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
- }
- }
- }
- }
- // Register bean as disposable.
- registerDisposableBeanIfNecessary(beanName, bean, mbd);
- return exposedObject;
- }
doCreateBean 的流程:
1. 會創建一個 BeanWrapper 對象 用于存放實例化對象。
2. 如果沒有指定構造函數,會通過反射拿到一個默認的構造函數對象,并賦予beanDefinition.resolvedConstructorOrFactoryMethod 。
3. 調用 spring 的 BeanUtils 的 instantiateClass 方法,通過反射創建對象。
4. applyMergedBeanDefinitionPostProcessors
5. populateBean(beanName, mbd, instanceWrapper); 根據注入方式進行注入。根據是否有依賴檢查進行依賴檢查。
執行 bean 的注入里面會選擇注入類型:
- if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
- mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
- MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
-
- // Add property values based on autowire by name if applicable.
- if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
- autowireByName(beanName, mbd, bw, newPvs);
- }<span style="color: #ff0000;">//根據名字注入</span>
-
-
-
-
-
- // Add property values based on autowire by type if applicable.
- if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
- autowireByType(beanName, mbd, bw, newPvs);
- }<span style="color: #ff0000;">//根據類型注入</span>
-
-
-
-
-
- pvs = newPvs;
- }
6. initializeBean(beanName, exposedObject, mbd);
判斷是否實現了 BeanNameAware 、 BeanClassLoaderAware 等 spring 提供的接口,如果實現了,進行默認的注入。同時判斷是否實現了 InitializingBean 接口,如果是的話,調用 afterPropertySet 方法。
- protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {
- if (bean instanceof BeanNameAware) {
- ((BeanNameAware) bean).setBeanName(beanName);
- }
- if (bean instanceof BeanClassLoaderAware) {
- ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
- }
- if (bean instanceof BeanFactoryAware) {
- ((BeanFactoryAware) bean).setBeanFactory(this);
- }
- Object wrappedBean = bean;
- if (mbd == null || !mbd.isSynthetic()) {
- wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
- }
- <span style="color: #ff0000;"> try {
- invokeInitMethods(beanName, wrappedBean, mbd);
- }</span>
-
-
-
-
- catch (Throwable ex) {
- throw new BeanCreationException(
- (mbd != null ? mbd.getResourceDescription() : null),
- beanName, "Invocation of init method failed", ex);
- }
-
- if (mbd == null || !mbd.isSynthetic()) {
- wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
- }
- return wrappedBean;
- }
其中invokeInitMethods實現如下:
- protected void invokeInitMethods(String beanName, Object bean, RootBeanDefinition mbd)
- throws Throwable {
-
- boolean isInitializingBean = (bean instanceof InitializingBean);
- if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
- if (logger.isDebugEnabled()) {
- logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
- }
- ((InitializingBean) bean).afterPropertiesSet();<span style="color: #ff0000;">//調用afterPropertiesSet方法</span>
-
-
-
-
- }
-
- String initMethodName = (mbd != null ? mbd.getInitMethodName() : null);
- if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
- !mbd.isExternallyManagedInitMethod(initMethodName)) {
- invokeCustomInitMethod(beanName, bean, initMethodName, mbd.isEnforceInitMethod());
- }
- }
總結
以上基本描述了 spring 容器的初始化過程和 bean 的創建過程。主要還是從大處著眼,很多細節沒有涉及到。代碼閱讀總體感覺就是 spring 的代碼抽象很好,結合結構讀起來還是蠻順利的。后面的學習將從細節著手。
下面源碼學習預告:
1. Spring 的聲明式標簽如實現
2. Spring aop 代理如何實現