public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
            this.prepareRefresh();//准备工作
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            try {
                this.postProcessBeanFactory(beanFactory);
                StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                beanPostProcess.end();
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                this.registerListeners();
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var10) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
                }

                this.destroyBeans();
                this.cancelRefresh(var10);
                throw var10;
            } finally {
                this.resetCommonCaches();
                contextRefresh.end();
            }

        }
    }

第一步

/**
	 * Prepare this context for refreshing, setting its startup date and
	 * active flag as well as performing any initialization of property sources.
	 */
/**
	 * 准备此上下文以进行刷新、设置其启动日期和活动标志以及执行属性源的任何初始化。
	 */
protected void prepareRefresh() {//准备刷新
		// Switch to active.
        // 切换active的处理状态,同时为了更加明确的表示出当前的Spring上下文状态也提供有一个closed标记
		this.startupDate = System.currentTimeMillis(); // 获取开始时间
		this.closed.set(false); // 启动的时候就需要将关闭状态设置为false
		this.active.set(true); // 启动的时候将启动的状态设置为true
        // 日志记录的处理判断
		if (logger.isDebugEnabled()) {
			if (logger.isTraceEnabled()) {
				logger.trace("Refreshing " + this);
			}
			else {
				logger.debug("Refreshing " + getDisplayName());
			}
		}

		// Initialize any placeholder property sources in the context environment.
        // 在Spring容器里面可以通过“<context>”命名空间配置所有要加载的资源信息
		initPropertySources();

		// Validate that all properties marked as required are resolvable:
		// see ConfigurablePropertyResolver#setRequiredProperties
        // 根据当前的配置环境进行一些必要的属性的验证处理
		getEnvironment().validateRequiredProperties();

		// Store pre-refresh ApplicationListeners...
		if (this.earlyApplicationListeners == null) { // 判断是否有早期的存储事件
			this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);// 如果发现集合内容为空,则需要立即准备出一个新的集合来(集合存在了才可以保存事件的监听)
		}
		else {// 此时已经存在有了事件的集合处理了
			// Reset local application listeners to pre-refresh state.
			this.applicationListeners.clear();// 清空已有的事件监听集合
			this.applicationListeners.addAll(this.earlyApplicationListeners);// 保存早期事件
		}

		// Allow for the collection of early ApplicationEvents,
		// to be published once the multicaster is available...
		this.earlyApplicationEvents = new LinkedHashSet<>();// 准备进行事件的发布处理
	}

面试题:请问在Spring容器里面启动耗时的统计操作是由那个方法发出开启的?

回答:在AbstractApplicatonContext类里面提供有一个startupDate属性,这个操作属性是在prepareRefresh()方法里面进行初始化定义的。

通过以上的准备刷新方法的源代码里面可以发现整个的Spring容器做了如下的几个操作准备:

进行一些标志位属性的定义(active、closed);

如果此时采用了DEBUG的日志模式,则要进行一些信息的输出;

考虑到项目里面会存在有一些资源配置(*.properties),所以需要进行所有资源配置的初始化处理;

通过Environment环境来实现一些属性的校验处理;

Spring之中提供有自定义事件的扩展机制,而此处就是进行事件的发布处理(事件监听集合可以在此处配置)。