1. 程式人生 > >spring4.1.8初始化原始碼學習三部曲之三:AbstractApplicationContext.refresh方法

spring4.1.8初始化原始碼學習三部曲之三:AbstractApplicationContext.refresh方法

本章是《spring4.1.8初始化原始碼學習三部曲》系列的終篇,重點是學習AbstractApplicationContext類的refresh()方法;

我們先回顧ClassPathXmlApplicationContext類的初始化過程如下程式碼:

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {
    super(parent);
    setConfigLocations(configLocations);
    if
(refresh) { refresh(); } }

refresh方法簡介

本章來學習refresh方法,具體的原始碼在AbstractApplicationContext類中,該方法的簡介請看下面原始碼中的註釋:

@Override
public void refresh() throws BeansException, IllegalStateException {
    //startupShutdownMonitor物件在spring環境重新整理和銷燬的時候都會用到,確保重新整理和銷燬不會同時執行
    synchronized (this.startupShutdownMonitor) {
        // 準備工作,例如記錄事件,設定標誌,檢查環境變數等,並有留給子類擴充套件的位置,用來將屬性加入到applicationContext中
prepareRefresh(); // 建立beanFactory,這個物件作為applicationContext的成員變數,可以被applicationContext拿來用, // 並且解析資源(例如xml檔案),取得bean的定義,放在beanFactory中 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 對beanFactory做一些設定,例如類載入器、spel解析器、指定bean的某些型別的成員變數對應某些物件等
prepareBeanFactory(beanFactory); try { // 子類擴充套件用,可以設定bean的後置處理器(bean在例項化之後這些後置處理器會執行) postProcessBeanFactory(beanFactory); // 執行beanFactory後置處理器(有別於bean後置處理器處理bean例項,beanFactory後置處理器處理bean定義) invokeBeanFactoryPostProcessors(beanFactory); // 將所有的bean的後置處理器排好序,但不會馬上用,bean例項化之後會用到 registerBeanPostProcessors(beanFactory); // 初始化國際化服務 initMessageSource(); // 建立事件廣播器 initApplicationEventMulticaster(); // 空方法,留給子類自己實現的,在例項化bean之前做一些ApplicationContext相關的操作 onRefresh(); // 註冊一部分特殊的事件監聽器,剩下的只是準備好名字,留待bean例項化完成後再註冊 registerListeners(); // 單例模式的bean的例項化、成員變數注入、初始化等工作都在此完成 finishBeanFactoryInitialization(beanFactory); // applicationContext重新整理完成後的處理,例如生命週期監聽器的回撥,廣播通知等 finishRefresh(); } catch (BeansException ex) { logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex); // 重新整理失敗後的處理,主要是將一些儲存環境資訊的集合做清理 destroyBeans(); // applicationContext是否已經啟用的標誌,設定為false cancelRefresh(ex); // Propagate exception to caller. throw ex; } } }

接下來逐個分析吧:

prepareRefresh方法

prepareRefresh方法的原始碼如下:

protected void prepareRefresh() {
    //記錄初始化開始時間
    this.startupDate = System.currentTimeMillis();
    //context是否關閉的標誌,設定為false
    this.closed.set(false);
    //context是否啟用的標誌,設定為true
    this.active.set(true);

    if (logger.isInfoEnabled()) {
        logger.info("Refreshing " + this);
    }

    //留給子類實現的空方法
    initPropertySources();

    /**
    AbstractPropertyResolver類的requiredProperties是個集合,
    在下面的validateRequiredProperties方法中,都要拿requiredProperties中的元素作為key去檢查是否存在對應的環境變數,
    如果不存在就丟擲異常
    */
    getEnvironment().validateRequiredProperties();
}

上述程式碼中,注意以下兩處:
1. initPropertySources是個空方法,是留給子類實現的,以AnnotationConfigWebApplicationContext類為例,就overwrite了initPropertySources方法:

@Override
protected void initPropertySources() {
    ConfigurableEnvironment env = getEnvironment();
    if (env instanceof ConfigurableWebEnvironment) {
        ((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, this.servletConfig);
    }
}

跟蹤上面的initPropertySources方法,最終找到了WebApplicationContextUtils.initServletPropertySources:

public static void initServletPropertySources(
            MutablePropertySources propertySources, ServletContext servletContext, ServletConfig servletConfig) {

        Assert.notNull(propertySources, "propertySources must not be null");
        if (servletContext != null && propertySources.contains(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME) &&
                propertySources.get(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME) instanceof StubPropertySource) {
            propertySources.replace(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME,
                    new ServletContextPropertySource(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME, servletContext));
        }
        if (servletConfig != null && propertySources.contains(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME) &&
                propertySources.get(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME) instanceof StubPropertySource) {
            propertySources.replace(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME,
                    new ServletConfigPropertySource(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME, servletConfig));
        }
    }

上面的程式碼所做的事情,就是給context增加環境變數資料(資料來自servlet相關的配置資訊),這樣spring環境就能從context中隨時key取得對應的變量了;

  1. getEnvironment().validateRequiredProperties()的作用是用來校驗context中是否存在“某些”變數,何謂”某些”?來看validateRequiredProperties方法,追蹤到多層呼叫,最終在AbstractPropertyResolver類的validateRequiredProperties方法中實現:
@Override
public void validateRequiredProperties() {
    MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();
    for (String key : this.requiredProperties) {
        if (this.getProperty(key) == null) {
            ex.addMissingRequiredProperty(key);
        }
    }
    if (!ex.getMissingRequiredProperties().isEmpty()) {
        throw ex;
    }
}

上述程式碼顯示,如果集合requiredProperties中的name在context中找不到對應的變數,就會丟擲異常;

那麼問題來了,requiredProperties集合是何時設定的呢?spring-framework中並沒有呼叫,但是官方的單元測試原始碼給我們了啟發,如下圖:
這裡寫圖片描述

如上圖紅框,如果業務需要確保某些變數在spring環境中必須存在,就可以呼叫setRequiredProperties方法將變數的name傳遞進去,這樣validateRequiredProperties方法就會做檢查了,我們可以基於現有的各種ApplicationContext實現自己定製一個Context類,確保在validateRequiredProperties方法呼叫之前呼叫setRequiredProperties方法將變數的name傳遞進去(例如重寫initPropertySources),就能讓spring幫我們完成檢查了;

obtainFreshBeanFactory()

接下來看ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();得到臨時變數beanFactory,先看看ConfigurableListableBeanFactory和BeanFactory的關係:
這裡寫圖片描述

再看看obtainFreshBeanFactory方法:

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    //由子類建立beanFactory
    refreshBeanFactory();
    //取得子類建立好的beanFactory,作為obtainFreshBeanFactory方法的返回值返回
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (logger.isDebugEnabled()) {
        logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
    }
    return beanFactory;
}

上述程式碼中有的refreshBeanFactory需要細看;

refreshBeanFactory方法

refreshBeanFactory方法,在AbstractApplicationContext類中是抽象方法,具體實現在子類中,以其子類AbstractRefreshableApplicationContext為例,我們來看看refreshBeanFactory方法的實現:

@Override
protected final void refreshBeanFactory() throws BeansException {
    //如果beanFactory已經存在,就銷燬context管理的所有bean,並關閉beanFactory
    if (hasBeanFactory()) {
        //其實就是呼叫一些集合的clear方法,解除對一些例項的引用,參考DefaultSingletonBeanRegistry.destroySingletons方法
        destroyBeans();
        //關閉當前的beanFactory,其實就是將成員變數beanFactory設定為null
        closeBeanFactory();
    }
    try {
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        beanFactory.setSerializationId(getId());
        customizeBeanFactory(beanFactory);
        loadBeanDefinitions(beanFactory);
        synchronized (this.beanFactoryMonitor) {
            this.beanFactory = beanFactory;
        }
    }
    catch (IOException ex) {
        throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    }
}
  1. createBeanFactory方法實際上返回的是一個DefaultListableBeanFactory例項:
protected DefaultListableBeanFactory createBeanFactory() {
    return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}


2. 接下來的customizeBeanFactory方法是留給子類OverWrite的,該方法的說明和原始碼如下,說明中推薦通過OverWrite的方式對現有beanFactory做特別的設定:

/**
* Customize the internal bean factory used by this context.
* Called for each {@link #refresh()} attempt.
* <p>The default implementation applies this context's
* {@linkplain #setAllowBeanDefinitionOverriding "allowBeanDefinitionOverriding"}
* and {@linkplain #setAllowCircularReferences "allowCircularReferences"} settings,
* if specified. Can be overridden in subclasses to customize any of
* {@link DefaultListableBeanFactory}'s settings.
* @param beanFactory the newly created bean factory for this context
* @see DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
* @see DefaultListableBeanFactory#setAllowCircularReferences
* @see DefaultListableBeanFactory#setAllowRawInjectionDespiteWrapping
* @see DefaultListableBeanFactory#setAllowEagerClassLoading
*/
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
    if (this.allowBeanDefinitionOverriding != null) {
        //allowBeanDefinitionOverriding表示是否允許註冊一個同名的類來覆蓋原有類(注意是類,不是例項)
        beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
    }
    if (this.allowCircularReferences != null) {
        //allowCircularReferences表示是否執行多個類之間的迴圈引用
        beanFactory.setAllowCircularReferences(this.allowCircularReferences);
    }
}


3. loadBeanDefinitions在AbstractRefreshableApplicationContext類中是個抽象方法,留給子類實現,作用是把所有bean的定義後儲存在context中,以AbstractXmlApplicationContext為例,看看loadBeanDefinitions方法做了什麼:

/**
* Loads the bean definitions via an XmlBeanDefinitionReader.
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
* @see #initBeanDefinitionReader
* @see #loadBeanDefinitions
*/
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    // Create a new XmlBeanDefinitionReader for the given BeanFactory.
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

    // Configure the bean definition reader with this context's
    // resource loading environment.
    beanDefinitionReader.setEnvironment(this.getEnvironment());
    beanDefinitionReader.setResourceLoader(this);
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

    // Allow a subclass to provide custom initialization of the reader,
    // then proceed with actually loading the bean definitions.
    initBeanDefinitionReader(beanDefinitionReader);
    loadBeanDefinitions(beanDefinitionReader);
}

以上程式碼可見,載入bean的定義是通過XmlBeanDefinitionReader 來完成的,重點關注loadBeanDefinitions方法:

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
    Resource[] configResources = getConfigResources();
    if (configResources != null) {
        reader.loadBeanDefinitions(configResources);
    }
    String[] configLocations = getConfigLocations();
    if (configLocations != null) {
        reader.loadBeanDefinitions(configLocations);
    }
}

上述程式碼中的getConfigResources()和getConfigLocations(),究竟哪個會返回值有效資料呢?這就要去看ClassPathXmlApplicationContext的構造方法了:

//這個方法設定的是configLocations 
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {

    super(parent);
    setConfigLocations(configLocations);
    if (refresh) {
        refresh();
    }
}

//這個方法設定的是這個方法設定的是configResources 
public ClassPathXmlApplicationContext(String[] paths, Class<?> clazz, ApplicationContext parent)
            throws BeansException {

    super(parent);
    Assert.notNull(paths, "Path array must not be null");
    Assert.notNull(clazz, "Class argument must not be null");
    this.configResources = new Resource[paths.length];
    for (int i = 0; i < paths.length; i++) {
        this.configResources[i] = new ClassPathResource(paths[i], clazz);
    }
    refresh();
}

因此,到底是configLocations 還是configResources ,和我們使用哪個構造方法來例項化applicationContext物件有關;

4. 如果我們例項化applicationContext物件的方式是new ClassPathXmlApplicationContext(“applicationContext.xml”),那麼setConfigLocations方法就會被呼叫,因此loadBeanDefinitions方法內部,實際執行的程式碼如下:

String[] configLocations = getConfigLocations();
    if (configLocations != null) {
        reader.loadBeanDefinitions(configLocations);
    }


5. 現在可以來看AbstractBeanDefinitionReader類的loadBeanDefinitions(String… locations)方法了:

public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
        Assert.notNull(locations, "Location array must not be null");
        int counter = 0;
        for (String location : locations) {
            counter += loadBeanDefinitions(location);
        }
        return counter;
    }

展開上面for迴圈中呼叫的方法:

public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
        ResourceLoader resourceLoader = getResourceLoader();
        if (resourceLoader == null) {
            throw new BeanDefinitionStoreException(
                    "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
        }

        if (resourceLoader instanceof ResourcePatternResolver) {
            // Resource pattern matching available.
            try {
                Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
                int loadCount = loadBeanDefinitions(resources);
                if (actualResources != null) {
                    for (Resource resource : resources) {
                        actualResources.add(resource);
                    }
                }
                if (logger.isDebugEnabled()) {
                    logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
                }
                return loadCount;
            }
            catch (IOException ex) {
                throw new BeanDefinitionStoreException(
                        "Could not resolve bean definition resource pattern [" + location + "]", ex);
            }
        }
        else {
            // Can only load single resources by absolute URL.
            Resource resource = resourceLoader.getResource(location);
            int loadCount = loadBeanDefinitions(resource);
            if (actualResources != null) {
                actualResources.add(resource);
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
            }
            return loadCount;
        }
    }

以上方法中,首先要記得resourceLoader是ClassPathXmlApplicationContext(beanDefinitionReader.setResourceLoader(this)這行程式碼),所有resourceLoader.getResource(location)這行程式碼最終會呼叫PathMatchingResourcePatternResolver類的getResources(String locationPattern)方法得到bean有關的Resource物件;
得到Resource物件後,接著會呼叫loadBeanDefinitions(Resource… resources)方法來載入bean的定義了,最終是呼叫XmlBeanDefinitionReader.loadBeanDefinitions(EncodedResource encodedResource)方法:

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        Assert.notNull(encodedResource, "EncodedResource must not be null");
        if (logger.isInfoEnabled()) {
            logger.info("Loading XML bean definitions from " + encodedResource.getResource());
        }

        Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
        if (currentResources == null) {
            currentResources = new HashSet<EncodedResource>(4);
            this.resourcesCurrentlyBeingLoaded.set(currentResources);
        }
        if (!currentResources.add(encodedResource)) {
            throw new BeanDefinitionStoreException(
                    "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        }
        try {
            InputStream inputStream = encodedResource.getResource().getInputStream();
            try {
                InputSource inputSource = new InputSource(inputStream);
                if (encodedResource.getEncoding() != null) {
                    inputSource.setEncoding(encodedResource.getEncoding());
                }
                return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
            }
            finally {
                inputStream.close();
            }
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException(
                    "IOException parsing XML document from " + encodedResource.getResource(), ex);
        }
        finally {
            currentResources.remove(encodedResource);
            if (currentResources.isEmpty()) {
                this.resourcesCurrentlyBeingLoaded.remove();
            }
        }
    }

上述程式碼可見,重要的是通過Resource物件得到InputStream,再呼叫doLoadBeanDefinitions方法:

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {
        try {
            Document doc = doLoadDocument(inputSource, resource);
            return registerBeanDefinitions(doc, resource);
        }
        ...

上面是載入bean定義的關鍵程式碼:先製作Document物件,再呼叫registerBeanDefinitions方法,最終會將每個bean的定義放入DefaultListableBeanFactory的beanDefinitionMap中,詳細的堆疊如下圖:
這裡寫圖片描述

完成了bean定義的註冊,可以回到AbstractRefreshableApplicationContext.refreshBeanFactory方法了,看看loadBeanDefinitions(beanFactory)之後的程式碼:

synchronized (this.beanFactoryMonitor) {
            this.beanFactory = beanFactory;
        }

至此,refreshBeanFactory方法分析完畢,該方法所做的事情:把xml檔案中的bean定義被解析後,存放在DefaultListableBeanFactory的beanDefinitionMap中;

現在回到主線的AbstractApplicationContext.refresh()方法內,obtainFreshBeanFactory()我們已經分析完畢,所有bean定義都被存放在beanFactory這個臨時變數對應的例項中;

prepareBeanFactory

接下來是prepareBeanFactory(beanFactory),看一下此方法的原始碼:

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    //設定類載入器
    beanFactory.setBeanClassLoader(getClassLoader());
    //設定解析器,用於解析bean的定義中出現的Spel表示式表示式
    beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
    //設定一個註冊介面,該介面只有一個方法registerCustomEditors,用來設定自定義的轉換器
    beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

    // 部署一個bean的後置處理器ApplicationContextAwareProcessor,用於將spring的環境資訊注入到例項化的bean之中
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    //bean在初始化的時候,如果有屬性的型別為ResourceLoaderAware,則該屬性不會被依賴注入
    beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
    beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
    beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
    beanFactory.ignoreDependencyInterface(EnvironmentAware.class);

    // BeanFactory interface not registered as resolvable type in a plain factory.
    // MessageSource registered (and found for autowiring) as a bean.
    //bean如果有個屬性的型別為BeanFactory.class,那麼該屬性會被設定為beanFactory
    beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
    beanFactory.registerResolvableDependency(ResourceLoader.class, this);
    beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
    beanFactory.registerResolvableDependency(ApplicationContext.class, this);

    // Detect a LoadTimeWeaver and prepare for weaving, if found.
    if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        // 部署一個bean的後置處理器ApplicationContextAwareProcessor,用於AOP靜態代理相關的處理
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        // Set a temporary ClassLoader for type matching.
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }

    // Register default environment beans.
    if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
        //註冊一個bean
        beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
    }
    if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
        beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
    }
}

上述程式碼中有以下幾點需要注意:
1. beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())),此方法要配合AbstractBeanFactory.registerCustomEditors方法一起看更好理解:addPropertyEditorRegistrar方法向propertyEditorRegistrars屬性中放入了一個registrar,之後呼叫registerCustomEditors方法的時候,會用到propertyEditorRegistrars中的registrar,呼叫這些registrar的registerCustomEditors方法,完成自定義的轉換器的設定;
2. beanFactory.addBeanPostProcessor方法用來注入後置處理器,在bean例項被建立後,初始化方法被執行的前後,後置處理器的postProcessBeforeInitialization、postProcessAfterInitialization這兩個方法會分別被呼叫;
3. beanFactory.ignoreDependencyInterface設定了依賴注入時要忽略的介面,例如bean有個屬性型別是ResourceLoaderAware,那麼該屬性不會被注入ResourceLoaderAware型別的例項;
4. beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory)是特殊設定,如果一個bean有個屬性的型別是BeanFactory,那麼該屬性會被設定為beanFactory這個例項;

總的來說prepareBeanFactory方法就是為beanFactory做一些設定工作,傳入一些後面會用到的引數和工具類,再在spring容器中建立一些bean;

postProcessBeanFactory

postProcessBeanFactory方法是留給子類擴充套件的,可以在bean例項初始化之前註冊後置處理器(類似prepareBeanFactory方法中的beanFactory.addBeanPostProcessor),以子類AbstractRefreshableWebApplicationContext為例,其postProcessBeanFactory方法如下:

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
        beanFactory.ignoreDependencyInterface(ServletContextAware.class);
        beanFactory.ignoreDependencyInterface(ServletConfigAware.class);

        WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
        WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
    }

可見除了WebApplicationContextUtils類的工作之外,其餘的都是和prepareBeanFactory方法中類似的處理;

invokeBeanFactoryPostProcessors

invokeBeanFactoryPostProcessors方法用來執行BeanFactory例項的後置處理器BeanFactoryPostProcessor的postProcessBeanFactory方法,這個後置處理器除了原生的,我們也可以自己擴充套件,用來對Bean的定義做一些修改,由於此時bean還沒有例項化,所以不要在自己擴充套件的BeanFactoryPostProcessor中呼叫那些會觸發bean例項化的方法(例如BeanFactory的getBeanNamesForType方法),原始碼的文件中有相關說明,如下圖紅框所示,不要觸發bean的例項化,如果要處理bean例項請在BeanPostProcessor中進行;:
這裡寫圖片描述

registerBeanPostProcessors

registerBeanPostProcessors方法的程式碼略多,就不在此貼出來了,簡單的說,就是找出所有的bean的後置處理器(注意,是bean的後置處理器,不是beanFactory的後置處理器,bean後置處理器處理的是bean例項,beanfactory後置處理器處理的是bean的定義),然後將這些bean的後置處理器分為三類:
1. 實現了順序介面Ordered.class的,先放入orderedPostProcessors集合,排序後順序加入beanFactory的bean後處理集合中;
2. 既沒有實現Ordered.class,也沒有實現PriorityOrdered.class的後置處理器,也加入到beanFactory的bean後處理集合中;
3. 最後是實現了優先順序介面PriorityOrdered.class的,排序後順序加入beanFactory的bean後處理集合中;

registerBeanPostProcessors方法執行完畢後,beanFactory中已經儲存了有序的bean後置處理器,在bean例項化之後,會依次使用這些後置處理器對bean例項來做對應的處理;

initMessageSource

initMessageSource方法用來準備國際化資源相關的,將實現了MessageSource介面的bean存放在ApplicationContext的成員變數中,先看是否有配置,如果有就例項化,否則就建立一個DelegatingMessageSource例項的bean;

initApplicationEventMulticaster

spring中有事件、事件廣播器、事件監聽器等組成事件體系,在initApplicationEventMulticaster方法中對事件廣播器做初始化,如果找不到此bean的配置,就建立一個SimpleApplicationEventMulticaster例項作為事件廣播器的bean,並且儲存為applicationContext的成員變數applicationEventMulticaster;

onRefresh

onRefresh是個空方法,留給子類自己實現的,在例項化bean之前做一些ApplicationContext相關的操作,以子類AbstractRefreshableWebApplicationContext為例,看看它的onRefresh方法:

@Override
protected void onRefresh() {
    this.themeSource = UiApplicationContextUtils.initThemeSource(this);
}

可見是做了主題相關的初始化,並儲存在ApplicationContext的成員變數中;

registerListeners

方法名為registerListeners,看名字像是將監聽器註冊在事件廣播器中,但實際情況並非如此,只有一些特殊的監聽器被註冊了,那些在bean配置檔案中實現了ApplicationListener介面的類還沒有例項化,所以此處只是將其name儲存在廣播器中,將這些監聽器註冊在廣播器的操作是在bean的後置處理器中完成的,那時候bean已經例項化完成了,我們看程式碼:

protected void registerListeners() {
    // 註冊的都是特殊的事件監聽器,而並非配置中的bean
    for (ApplicationListener<?> listener : getApplicationListeners()) {
        getApplicationEventMulticaster().addApplicationListener(listener);
    }

    // Do not initialize FactoryBeans here: We need to leave all regular beans
    // uninitialized to let post-processors apply to them!
    // 根據介面型別找出所有監聽器的名稱
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    for (String listenerBeanName : listenerBeanNames) {
        // 這裡只是把監聽器的名稱儲存在廣播器中,並沒有將這些監聽器例項化!!!
        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
    }
}

finishBeanFactoryInitialization

finishBeanFactoryInitialization方法做了兩件事:
1. beanFactory物件的初始化;
2. 我們在bean配置檔案中配置的那些單例的bean,都是在finishBeanFactoryInitialization方法中例項化的;

看程式碼:

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // Initialize conversion service for this context.
    // 例項化型別轉換的bean,並儲存在ApplicationContext中
    if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
            beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
        beanFactory.setConversionService(
        beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
    }

    // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
    // 例項化LoadTimeWeaverAware介面的bean,用於ApsectJ的類載入期織入的處理
    String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
    for (String weaverAwareName : weaverAwareNames) {
        getBean(weaverAwareName);
    }

    // Stop using the temporary ClassLoader for type matching.
    // 確保臨時的classLoader為空,臨時classLoader一般被用來做型別匹配的
    beanFactory.setTempClassLoader(null);

    // Allow for caching all bean definition metadata, not expecting further changes.
    // 將一個標誌設定為true,表示applicationContext已經快取了所有bean的定義,這些bean的name都被儲存在applicationContext的frozenBeanDefinitionNames成員變數中,相當於一個快照,記錄了當前那些bean的定義已經拿到了
    beanFactory.freezeConfiguration();

    // 例項化所有還未例項化的單例bean
    beanFactory.preInstantiateSingletons();
}

上述程式碼中,beanFactory.preInstantiateSingletons()需要展開仔細看:

public void preInstantiateSingletons() throws BeansException {
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Pre-instantiating singletons in " + this);
        }

        // Iterate over a copy to allow for init methods which in turn register new bean definitions.
        // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
        List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);

        // Trigger initialization of all non-lazy singleton beans...
        for (String beanName : beanNames) {
            // 獲取bean的定義,該定義已經和父類定義做了合併
            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            // 非抽象類、是單例、非懶載入
            if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                //FactoryBean的處理
                if (isFactoryBean(beanName)) {
                    final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
                    boolean isEagerInit;
                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                        isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                            @Override
                            public Boolean run() {
                                return ((SmartFactoryBean<?>) factory).isEagerInit();
                            }
                        }, getAccessControlContext());
                    }
                    else {
                        isEagerInit = (factory instanceof SmartFactoryBean &&
                                ((SmartFactoryBean<?>) factory).isEagerInit());
                    }
                    if (isEagerInit) {
                        getBean(beanName);
                    }
                }
                else {
                    //非FactoryBean的例項化、初始化
                    getBean(beanName);
                }
            }
        }

        // Trigger post-initialization callback for all applicable beans...
        // 單例例項化完成後,如果實現了SmartInitializingSingleton介面,afterSingletonsInstantiated就會被呼叫,此處用到了特權控制邏輯AccessController.doPrivileged
        for (String beanName : beanNames) {
            Object singletonInstance = getSingleton(beanName);
            if (singletonInstance instanceof SmartInitializingSingleton) {
                final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
                if (System.getSecurityManager() != null) {
                    AccessController.doPrivileged(new PrivilegedAction<Object>() {
                        @Override
                        public Object run() {
                            smartSingleton.afterSingletonsInstantiated();
                            return null;
                        }
                    }, getAccessControlContext());
                }
                else {
                    smartSingleton.afterSingletonsInstantiated();
            }
        }
    }
}

上述程式碼中,要重點關注getBean(beanName),這裡面會例項化bean,由於內容太多不適合在本章細說,這裡先將例項化bean的呼叫路徑整理出來:

AbstractBeanFactory.getBean(String name)

->

AbstractBeanFactory.doGetBean(String name, Class<T> requiredType, final Object[] args, boolean typeCheckOnly)

->

DefaultSingletonBeanRegistry.getSingleton(String beanName, ObjectFactory<?> singletonFactory)

->

AbstractBeanFactory.doGetBean中的匿名類的getObject方法

->

AbstractAutowireCapableBeanFactory.createBean(String beanName, RootBeanDefinition mbd, Object[] args) 

->
AbstractAutowireCapableBeanFactory.doCreateBean(final String beanName, final RootBeanDefinition mbd, Object[] args)

->

AbstractAutowireCapableBeanFactory.createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args)

->

instantiateBean(final String beanName, final RootBeanDefinition mbd)

->

SimpleInstantiationStrategy.instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner)

->

BeanUtils.instantiateClass(Constructor<T> ctor, Object... args)

->

Constructor.newInstance(Object ... initargs)

->

bean的構造方法

以上呼叫路徑可以看出,bean物件的建立是BeanUtils.instantiateClass方法通過反射來建立的;

再來看看bean的成員變數是什麼時候被注入值的,如下圖,AbstractAutowireCapableBeanFactory.doCreateBean方法中,先呼叫createBeanInstance建立bean的物件(綠框所示),再呼叫populateBean方法給成員變數注入內容(紅框所示):

這裡寫圖片描述

將注入值的呼叫堆疊整理如下,可見是也是通過反射完成注入的:

AbstractAutowireCapableBeanFactory.populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw)

->

AbstractAutowireCapableBeanFactory.applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs)

->

AbstractPropertyAccessor.setPropertyValues(PropertyValues pvs)

->

BeanWrapperImpl.setPropertyValue(PropertyValue pv)

->

Method.invoke(Object obj, Object... args)

看過了成員變數注入的邏輯後,還有個重要的邏輯也請關注,就是bean的初始化(bean的配置檔案中的init-method屬性),AbstractAutowireCapableBeanFactory.doCreateBean方法中,在呼叫populateBean方法給成員變數注入值之後,馬上呼叫initializeBean方法進行初始化操作,呼叫堆疊整理如下:

AbstractAutowireCapableBeanFactory.initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd)

->

AbstractAutowireCapableBeanFactory.invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)

->

AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd)

->

Method.invoke(Object obj, Object... args)

可見依舊是通過反射來執行初始化方法;

finishRefresh

最後一個方法是finishRefresh,這是在bean的例項化、初始化等完成後的一些操作,例如生命週期變更的回撥,傳送applicationContext重新整理完成的廣播等,展開看看:

protected void finishRefresh() {
    // 檢查是否已經配置了生命週期處理器,如果沒有就new一個DefaultLifecycleProcessor
    initLifecycleProcessor();

    // 找到所有實現了Lifecycle介面的bean,按照每個bean設定的生命週期階段進行分組,再依次呼叫每個分組中每個bean的start方法,完成生命週期監聽的通知
    getLifecycleProcessor().onRefresh();

    // 建立一條代表applicationContext重新整理完成的事件,交給廣播器去廣播
    publishEvent(new ContextRefreshedEvent(this));

    // 如果配置了MBeanServer,就完成在MBeanServer上的註冊
    LiveBeansView.registerApplicationContext(this);
}

至此,整個初始化流程咱們已經過了一遍了,但是篇幅有限,很多細節都沒有展開,另外很多子類也有自己獨特的擴充套件,這些都需要花時間去細看,希望本文能幫您整理思路,從總體上了解初始化的各個關鍵步驟,以免過早陷入細節;