天天看點

了解 Spring 應用上下文生命周期

作者:阿裡開發者
Spring 應用上下文(ApplicationContext),是 Spring 應用的核心接口,也是我們常說的 Spring 容器,除了擴充了基礎容器 BeanFactory 還提供了更多企業級的特性,如資源管理、事件釋出、國際化等。

前言

Spring 應用上下文(ApplicationContext),是 Spring 應用的核心接口,也是我們常說的 Spring 容器,除了擴充了基礎容器 BeanFactory 還提供了更多企業級的特性,如資源管理、事件釋出、國際化等。了解 Spring 應用上下文的生命周期也就了解了 Spring 内部的運作的核心邏輯,生命周期中同時提供了很多擴充點,跟随文章,我們一探究竟。

應用上下文的生命周期

Spring ApplicationContext 具有層次性的設計,生命周期的管理主要在 AbstractApplicationContext,類圖如下。

了解 Spring 應用上下文生命周期

生命周期的相關方法均由實作的接口提供,各生命周期階段并非完整地從上而下執行,部分階段是可選的,具體如下。

重新整理階段:org.springframework.context.ConfigurableApplicationContext#refresh

啟動階段:org.springframework.context.Lifecycle#start

停止階段:org.springframework.context.Lifecycle#stop

關閉階段:org.springframework.context.ConfigurableApplicationContext#close

重新整理階段

重新整理階段是 Spring 應用上下文生命周期的主要階段,重新整理階段完成後 Spring 中的非延遲單例 bean 即執行個體化完成,依賴注入也完成,可以正常調用 bean 的方法。有關 bean 的生命周期可參考我前面的文章《Java 面試必備的 Spring Bean 生命周期總結》。

重新整理階段對應的 AbstractApplicationContext#refresh 方法源碼如下。

@Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 應用上下文重新整理準備
            prepareRefresh();

            // BeanFactory 建立
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // BeanFactory 準備
            prepareBeanFactory(beanFactory);

            try {
                // BeanFactory 後處理,由子類擴充
                postProcessBeanFactory(beanFactory);

                // BeanFactory 後處理,調用 BeanFactoryPostProcessor 方法
                invokeBeanFactoryPostProcessors(beanFactory);

                // 注冊 BeanPostProcessor
                registerBeanPostProcessors(beanFactory);

                // 初始化 MessageSource
                initMessageSource();

                // 初始化事件廣播器
                initApplicationEventMulticaster();

                // 上下文重新整理
                onRefresh();

                // 注冊事件監聽器
                registerListeners();

                // 初始化完成,執行個體化所有非延遲初始化的單例 bean
                finishBeanFactoryInitialization(beanFactory);

                // 重新整理完成
                finishRefresh();
            } catch (BeansException ex) {
                destroyBeans();
                cancelRefresh(ex);
                throw ex;
            } finally {
                resetCommonCaches();
            }
        }
    }           

下面對應用上下文的重新整理階段進行細化分析。

上下文重新整理準備階段

上下文重新整理準備階段的工作如下:

設定啟動時間及狀态辨別。

初始化 PropertySource。

由子類進行擴充,web 環境下将初始化名稱為 servletContextInitParams 和 servletConfigInitParams 的 PropertySource 。

關于 PropertySource 可參見我前面的文章《Spring 中的 Environment 、Profile 與 PropertySource》。

校驗 Environment 中必須的屬性。

初始化事件監聽器集合。

關于 Spring 事件可參見我前面的文章《Spring 事件處理機制詳解,帶你吃透 Spring 事件》 。

初始化早期事件集合。

對應的AbstractApplicationContext#prepareRefresh方法源碼如下。

protected void prepareRefresh() {
        // 設定重新整理事件及激活狀态
        this.startupDate = System.currentTimeMillis();
        this.closed.set(false);
        this.active.set(true);
        
        ... 省略日志列印代碼

        // 初始化 Environment 中的 PropertySource,該方法為空方法,由子類實作,如 web 環境下添加 ServletContext 初始化及 Servlet 配置的 PropertySource
        initPropertySources();

        // 校驗 Environment 設定的必須的屬性
        getEnvironment().validateRequiredProperties();

        if (this.earlyApplicationListeners == null) {
            // 首次 fresh,把重新整理前添加的監聽器添加到 earlyApplicationListeners
            this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
        } else {
            // 再次 fresh,把之前添加的監聽器添加到 applicationListeners
            this.applicationListeners.clear();
            this.applicationListeners.addAll(this.earlyApplicationListeners);
        }

        // 初始化事件集合,事件廣播器初始化完成後釋出
        this.earlyApplicationEvents = new LinkedHashSet<>();
    }           

BeanFactory 建立階段

BeanFactory 建立階段的工作如下:

重新整理 BeanFactory。

銷毀并關閉 BeanFactory,如果已存在。

建立 BeanFactory。

設定 BeanFactory 的 ID。

設定 BeanFactory 是否允許 BeanDefinition 重複注冊及循環引用。

關于循環引用,可參見我前面的文章《Spring 循環依賴處理》。

加載 BeanDefinition。

抽象方法,由子類進行實作。XML 和注解方式加載 BeanDefinition 的方式有所不同。

關于 BeanDefinition,可參見我前面的文章《掌握 Spring 必須知道的 BeanDefinition》 。

關聯 BeanFactory 到應用上下文。

擷取 BeanFactory。

相關的源碼說明如下所示。

// AbstractApplicationContext#obtainFreshBeanFactory
  protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    // 先建立 BeanFactory,該方法為抽象方法,由子類進行實作
    refreshBeanFactory();
    // 再擷取 BeanFactory
    return getBeanFactory();
  }

  // AbstractRefreshableApplicationContext#refreshBeanFactory
  @Override
  protected final void refreshBeanFactory() throws BeansException {
    if (hasBeanFactory()) {
      // 如果已經存在 BeanFactory,先銷毀 bean ,然後關閉 BeanFactory
      destroyBeans();
      closeBeanFactory();
    }
    try {
      // 建立 BeanFactory
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      beanFactory.setSerializationId(getId());
      // 設定是否允許重複注冊 BeanDefinition,是否允許循環引用
      customizeBeanFactory(beanFactory);
      // 加載 BeanDefinition,抽象方法,由子類進行實作
      loadBeanDefinitions(beanFactory);
      synchronized (this.beanFactoryMonitor) {
        this.beanFactory = beanFactory;
      }
    } catch (IOException ex) {
      throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    }
  }           

BeanFactory 準備階段

BeanFactory 準備階段的工作如下:

設定加載 bean class 的 ClassLoader。

設定解析 BeanDefinition 中字元串的表達式處理器。

添加 PropertyEditorRegistrar 的實作 ResourceEditorRegistrar。

添加 Aware 回調接口 BeanPostProcessor 的實作 ApplicationContextAwareProcessor。

支援的 Aware 回調接口包括 EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware。

忽略 Aware 回調接口作為依賴注入接口。

忽略的 Aware 回調接口和上面 ApplicationContextAwareProcessor 支援的 Aware 回調接口相對應,保持一緻。

注冊 ResolvableDependency 對象作為 bean。

包括 BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext。

添加 BeanPostProcessor 的實作 ApplicationListenerDetector。用于将 ApplicationListener 添加到 ApplicationContext。

如果 BeanFactory 中存在名稱為 loadTimeWeaver 的 bean,

添加 BeanPostProcessor 的實作 LoadTimeWeaverAwareProcessor。

設定臨時類加載器 ContextTypeMatchClassLoader。

注冊單例 bean Environment、Java System Properties、OS 環境變量。

相關的源碼說明如下所示:

// AbstractApplicationContext#prepareBeanFactory
    protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // 設定類加載器、表達式處理器;添加 ResourceEditorRegistrar
        beanFactory.setBeanClassLoader(getClassLoader());
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

        // 配置 Aware 回調接口的處理器 ApplicationContextAwareProcessor,并且忽略依賴注入對應的 Aware 接口
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
        beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
        beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
        beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
        beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

        // 注冊依賴注入時可解析的依賴
        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
        beanFactory.registerResolvableDependency(ResourceLoader.class, this);
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        beanFactory.registerResolvableDependency(ApplicationContext.class, this);

        // 添加 ApplicationListenerDetector,用于添加事件監聽器到應用上下文
        beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

        // AOP 相關
        if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            // Set a temporary ClassLoader for type matching.
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }

        // 注冊預設的環境相關的單例 bean
        if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
            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());
        }
    }           

BeanFactory 後置處理階段

BeanFactory 後置處理階段的工作如下:

調用方法 postProcessBeanFactory。

該方法實作為空,由子類進行擴充。

如 web 環境下會設定 ServletContextAware、ServletConfigAware 回調處理,注冊 web 環境下的 scope 及相關的 bean。

調用 BeanFactoryPostProcessor 中的後置處理方法。

如果臨時 ClassLoader 不存在并且存在名稱為 loadTimeWeaver 的 bean,

添加 BeanPostProcessor 的實作 LoadTimeWeaverAwareProcessor。

設定臨時類加載器 ContextTypeMatchClassLoader。

相關的源碼如下:

// AbstractRefreshableWebApplicationContext#postProcessBeanFactory
    protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // 添加 web 環境下 aware 處理,忽略 aware 依賴注入接口
        beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
        beanFactory.ignoreDependencyInterface(ServletContextAware.class);
        beanFactory.ignoreDependencyInterface(ServletConfigAware.class);

        // 注冊 web 環境下的 scope
        WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
        // 注冊 web 環境下的 bean
        WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
    }
    
    // AbstractApplicationContext#invokeBeanFactoryPostProcessors
    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        // 調用 BeanFactoryPostProcessor 處理方法  
        PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

        // AOP 相關
        if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }
    }           

BeanPostProcessor 注冊階段

BeanPostProcessor 注冊階段的工作主要是将 BeanPostProcessor 類型的 bean 添加到 BeanFactory 内部持有的 BeanPostProcessor 清單中。添加順序如下:

實作 PriorityOrdered 接口的 BeanPostProcessor。

實作 Ordered 接口的 BeanPostProcessor。

普通的 BeanPostProcessor。

實作 MergedBeanDefinitionPostProcessor 接口的 BeanPostProcessor。

ApplicationListenerDetector 接口。

相關的源碼如下:

// AbstractApplicationContext#registerBeanPostProcessors
    protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
    }           

MessageSource 初始化階段

MessageSource 初始化階段用于保證 BeanFactory 中存在 MessageSource 類型的單例 bean。關于 MessageSource,可參見我前面的文章《Spring 國際化支援之 MessageSource》。

相關的源碼如下:

protected void initMessageSource() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
            // 設定 messageSource 到目前應用上下文
            this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
            // 設定父 MessageSource
            if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
                HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
                if (hms.getParentMessageSource() == null) {
                    hms.setParentMessageSource(getInternalParentMessageSource());
                }
            }
        } else {
            // 設定 MessageSource 到目前應用上下文,通過調用父 MessageSource 實作其功能
            DelegatingMessageSource dms = new DelegatingMessageSource();
            dms.setParentMessageSource(getInternalParentMessageSource());
            this.messageSource = dms;
            beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
        }
    }           

事件廣播器初始化階段

事件廣播器初始化階段主要用來保證應用上下文中存在 ApplicationEventMulticaster。相關的源碼如下:

protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
            // 存在名稱為 applicationEventMulticaster 的 bean,設定到應用上下文
            this.applicationEventMulticaster =
                    beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
            }
        } else {
            // 不存在 bean,設定到目前應用上下文,并注冊為 bean
            this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
            beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
            }
        }
    }           

上下文重新整理階段

上下文重新整理階段對應的方法為AbstractApplicationContext#onRefresh,該方法為空方法,由子類進行實作。

事件監聽器注冊階段

事件監聽器注冊階段的工作如下:

添加目前應用上下文關聯的事件監聽器到廣播器。

添加 BeanFactory 中注冊的事件監聽器 bean 到廣播器。

廣播早期事件。

相關源代碼如下:

protected void registerListeners() {
        // 添加應用上下文中的事件監聽器到事件廣播器中
        for (ApplicationListener<?> listener : getApplicationListeners()) {
            getApplicationEventMulticaster().addApplicationListener(listener);
        }

        // 添加 BeanFactory 中注冊的事件監聽器到事件廣播器中
        String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
        for (String listenerBeanName : listenerBeanNames) {
            getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
        }

        // 釋出早期事件
        Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
        this.earlyApplicationEvents = null;
        if (earlyEventsToProcess != null) {
            for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
                // 廣播目前應用上下文重新整理前釋出的事件
                getApplicationEventMulticaster().multicastEvent(earlyEvent);
            }
        }
    }           

BeanFactory 初始化完成階段

BeanFactory 初始化完成階段的工作如下:

如果 BeanFactory 中存在注冊的名稱為 conversionService 的 ConversionService,将其設定到 BeanFactory 中。

如果 BeanFactory 中不存在 StringValueResolver,添加 StringValueResolver 到 BeanFactory。

點選檢視原文,擷取更多福利!

https://developer.aliyun.com/article/1086017?utm_content=g_1000365171

版權聲明:本文内容由阿裡雲實名注冊使用者自發貢獻,版權歸原作者所有,阿裡雲開發者社群不擁有其著作權,亦不承擔相應法律責任。具體規則請檢視《阿裡雲開發者社群使用者服務協定》和《阿裡雲開發者社群知識産權保護指引》。如果您發現本社群中有涉嫌抄襲的内容,填寫侵權投訴表單進行舉報,一經查實,本社群将立刻删除涉嫌侵權内容。