返回

剖析Spring源码中的prepareRefresh()方法

后端

Spring容器刷新流程概述

Spring容器的刷新是一个复杂的过程,涉及到众多组件的协同工作。容器刷新流程大致可分为以下几个步骤:

  1. 准备容器刷新(prepareRefresh):容器在刷新前需要进行一些准备工作,例如检查容器是否处于活动状态、是否有正在执行的任务等。
  2. 获取需要刷新的Bean(getRefreshBean):容器从上下文中获取需要刷新的Bean,这些Bean通常是那些在容器启动时创建的Bean。
  3. 关闭需要刷新的Bean(closeRefreshBeans):容器关闭需要刷新的Bean,释放它们持有的资源。
  4. 应用属性(applyProperties):容器将外部属性应用到需要刷新的Bean上。
  5. 初始化需要刷新的Bean(initializeRefreshBeans):容器初始化需要刷新的Bean,使其达到可用的状态。
  6. 完成容器刷新(finishBeanFactoryInitialization):容器完成对Bean的初始化,并执行其他必要的刷新操作,例如发布容器刷新事件等。

prepareRefresh()方法详解

prepareRefresh()方法是容器刷新流程的第一步,也是最关键的一步之一。该方法的主要任务是容器刷新前的准备工作,包括:

  1. 检查容器是否处于活动状态(isActive):容器在刷新前需要处于活动状态,如果容器处于非活动状态,则需要先将其激活。
  2. 检查是否有正在执行的任务(hasDestructionCallbacks):容器在刷新前需要确保没有正在执行的任务,如果有正在执行的任务,则需要先等待这些任务完成。
  3. 准备需要刷新的Bean(prepareRefreshBeans):容器为需要刷新的Bean做准备,包括将Bean的销毁回调函数标记为需要执行、将Bean的初始化回调函数标记为需要执行等。

prepareRefresh()方法的实现代码如下:

protected void prepareRefresh() {
    synchronized (this.startupShutdownMonitor) {
        // Check whether the context is still active.
        if (this.active.get() == false) {
            throw new IllegalStateException(
                    "Cannot call 'refresh' on a context that is already closed." +
                    " Call 'close' before 'refresh': context does not allow multiple refresh attempts: " + this);
        }

        // Check whether there is a running refresh in progress.
        if (this.startupShutdownMonitor.isRunning()) {
            throw new IllegalStateException(
                    "Cannot call 'prepareRefresh' while the context is being refreshed." +
                    " Consider defining a bean with an 'init-method' instead of a refresh callback: " + this);
        }

        this.startupShutdownMonitor.prepareRefresh();

        // Initialize cancellation semaphore.
        this.cancelRefresh = new LinkedBlockingQueue<>();

        // Prepare beans for refresh.
        try {
            prepareRefreshBeans();
        } catch (BeanDefinitionStoreException ex) {
            // Trigger failure scenario.
            throw new BeanCurrentlyInCreationException(ex.getBeanName(), ex);
        }

        // Initialize creation semaphore if necessary.
        if (this.containsBeanFactory() && !containsSingleton("scopedTarget.scopedTargetFactoryBean")) {
            this.creationBeanFactory = getBeanFactory();
        }

        // Allow for additional processing.
        invokeBeanFactoryPostProcessors(BeanFactoryPostProcessor.POST_PROCESS_BEFORE_REFRESH);

        // Prepare for bean definition validation.
        this.beanDefinitionValidator = createBeanDefinitionValidator();
    }
}

总结

prepareRefresh()方法是Spring容器刷新流程的第一步,也是最关键的一步之一。该方法的主要任务是容器刷新前的准备工作,包括检查容器是否处于活动状态、是否有正在执行的任务、准备需要刷新的Bean等。通过对prepareRefresh()方法的分析,我们可以更好地理解Spring容器的刷新过程,以及如何自定义容器的刷新行为。