Spring 中的 context

Spring 中的 context

BeanFactory

首先看下,官方在代碼中給出的註釋:css

The root interface for accessing a Spring bean container.This is the basic client view of a bean container。java

是接觸全部Spring bean容器的根接口,這個接口被持有大量bean定義的對象實現。spring

從其接口中定義的方法便可看出,其爲bean容器的真正含義。數據庫

ListableBeanFactory 繼承了 BeanFactory,爲其提供了枚舉全部 beans 的方法:app

ApplicationContext

而 ApplicationContext 類經過對該接口的擴展,提供了爲application提供配置的擴展接口。ide

根據官方給出的註釋,其總共功能有如下幾點:post

  1. 對應用的 component 的工廠方法;
  2. 一種通用的加載資源文件的方式;
  3. 對註冊的監聽器發佈事件的能力;
  4. 解析message,支持國家化的能力。

這些能力主要經過繼承各類接口得到,其自身接口主要擴展的重要方法主要有一個:性能

1@Nullable
2ApplicationContext getParent();
複製代碼

在 SpringBoot 中,context 有其繼承體系:每一個不一樣的 servlet 都有本身獨立的 context,而整個 application 有一個根 context,這個 context 是全部 servlet 所共享的ui

因此此處提供了得到父 context 的能力。this

ConfigurableApplicationContext

所有或者絕大多數 application 的context都會實現或者繼承該接口。

擴展了一些配置 context 的方法,可是該接口中的方法僅僅在應用啓動或者關閉時調用。

提供了set/get environment的方法;註冊監聽器的方法;固然還有最重要的 refresh 方法。

 1/**
2 * Load or refresh the persistent representation of the configuration,
3 * which might an XML file, properties file, or relational database schema.
4 * <p>As this is a startup method, it should destroy already created singletons
5 * if it fails, to avoid dangling resources. In other words, after invocation
6 * of that method, either all or no singletons at all should be instantiated.
7 * @throws BeansException if the bean factory could not be initialized
8 * @throws IllegalStateException if already initialized and multiple refresh
9 * attempts are not supported
10 */
11void refresh() throws BeansException, IllegalStateException;
複製代碼

從註釋中咱們能夠看到該方法的做用:

加載或者刷新持久層的配置資源,好比 xml、property 或者數據庫文件。

由於該方法在應用啓動時調用,因此若是失敗,則要銷燬掉全部已經建立好的單例對象。

換句話說就是:一旦該方法被調用,要麼建立好全部的單例對象,要麼一個單例對象都不會建立

AbstractApplicationContext

對於 ConfigurableApplicationContext,該抽象類提供了大部分的模板實現方法。

這裏重點看下 refresh 方法:

 1@Override
2public void refresh() throws BeansException, IllegalStateException {
3   synchronized (this.startupShutdownMonitor) {
4      // Prepare this context for refreshing.
5      prepareRefresh();
6
7      // Tell the subclass to refresh the internal bean factory.
8      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
9
10      // Prepare the bean factory for use in this context.
11      prepareBeanFactory(beanFactory);
12
13      try {
14         // Allows post-processing of the bean factory in context subclasses.
15         postProcessBeanFactory(beanFactory);
16
17         // Invoke factory processors registered as beans in the context.
18         invokeBeanFactoryPostProcessors(beanFactory);
19
20         // Register bean processors that intercept bean creation.
21         registerBeanPostProcessors(beanFactory);
22
23         // Initialize message source for this context.
24         initMessageSource();
25
26         // Initialize event multicaster for this context.
27         initApplicationEventMulticaster();
28
29         // Initialize other special beans in specific context subclasses.
30         onRefresh();
31
32         // Check for listener beans and register them.
33         registerListeners();
34
35         // Instantiate all remaining (non-lazy-init) singletons.
36         finishBeanFactoryInitialization(beanFactory);
37
38         // Last step: publish corresponding event.
39         finishRefresh();
40      }
41
42      catch (BeansException ex) {
43         if (logger.isWarnEnabled()) {
44            logger.warn("Exception encountered during context initialization - " +
45                  "cancelling refresh attempt: " + ex);
46         }
47
48         // Destroy already created singletons to avoid dangling resources.
49         destroyBeans();
50
51         // Reset 'active' flag.
52         cancelRefresh(ex);
53
54         // Propagate exception to caller.
55         throw ex;
56      }
57
58      finally {
59         // Reset common introspection caches in Spring's core, since we
60         // might not ever need metadata for singleton beans anymore...
61         resetCommonCaches();
62      }
63   }
複製代碼

該方法比較長,可是註釋仍是比較詳細的,咱們能夠逐塊分解的看:

先看第5行(如下提到具體的行數均指的是 refresh 方法中的)中的prepareRefresh:

 1protected void prepareRefresh() {
2   // 設置一些容器 active flag 標誌位
3   this.startupDate = System.currentTimeMillis();
4   this.closed.set(false);
5   this.active.set(true);
6
7   // 初始化一些 environment 中的佔位符屬性
8   initPropertySources();
9
10   // 校驗一些標記爲 required 的必要屬性
11   getEnvironment().validateRequiredProperties();
12
13   // 存儲「準備刷新」的一些監聽器.
14   if (this.earlyApplicationListeners == null) {
15      this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
16   }
17   else {
18      // Reset local application listeners to pre-refresh state.
19      this.applicationListeners.clear();
20      this.applicationListeners.addAll(this.earlyApplicationListeners);
21   }
22
23   // 存儲事件
24   this.earlyApplicationEvents = new LinkedHashSet<>();
25}
複製代碼

繼續看第8行的代碼 obtainFreshBeanFactory 發生了什麼:

1protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
2   refreshBeanFactory();
3   return getBeanFactory();
4}
複製代碼

這裏使用了模板方法,refreshBeanFactory 的實現留給子類,官方給出的註釋是:

1/**
2 * 子類必須實現該方法來執行實際的加載工做。
3 */

4protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;
複製代碼

getBeanFactory 方法的實現也留給子類,官方的註釋是:

1/**
2 * 子類在這裏必須返回它內部的bean factory. 
3 * 這個bean factory 應該實現高效的查詢工做,這樣重複調用時纔不會形成性能損失.
4 * 注意:
5 * 子類在返回 bean factory 以前必須檢查 context 是否屬於 active 狀態;若是處於 close 狀態,則不能獲取該對象。
6 */

7@Override
8public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
複製代碼

第 11 行,prepareBeanFactory 方法:

對於一些 context 的特徵給出了配置,好比加載器、post-processor等。

 1protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
2   //設置加載器
3   beanFactory.setBeanClassLoader(getClassLoader());
4   //設置 Spring EL 解析器
5   beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
6   //設置用於註冊 PropertyEditor 的註冊機
7   beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
8
9   // Configure the bean factory with context callbacks.
10   // 設置一些用於 bean 後期處理的 processor
11   beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
12   // 忽略一些依賴接口
13   beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
14   beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
15   beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
16   beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
17   beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
18   beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
19
20   // BeanFactory interface not registered as resolvable type in a plain factory.
21   // MessageSource registered (and found for autowiring) as a bean.
22   // 註冊具備相應自動裝配值得依賴類型
23   beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
24   beanFactory.registerResolvableDependency(ResourceLoader.classthis);
25   beanFactory.registerResolvableDependency(ApplicationEventPublisher.classthis);
26   beanFactory.registerResolvableDependency(ApplicationContext.classthis);
27
28   // 註冊該監聽器用於檢測監聽器 bean
29   beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
30
31   // Detect a LoadTimeWeaver and prepare for weaving, if found.
32   if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
33      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
34      // Set a temporary ClassLoader for type matching.
35      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
36   }
37
38   // 註冊默認的 environment beans.
39   if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
40      beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
41   }
42   if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
43      beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
44   }
45   if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
46      beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
47   }
48}
複製代碼

第15行 postProcessBeanFactory 方法:

1protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
2}
複製代碼

也是一個模板方法,官方給出的註釋是:

context 內部的 bean factory 初始化後,在此處進行一些修改。此時全部的bean定義都被加載,可是尚未任何一個bean被實例化。

第 18 行invokeBeanFactoryPostProcessors方法:

 1protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory{
2   PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
3
4   // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
5   // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
6   if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
7      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
8      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
9   }
10}
複製代碼

此方法的做用在於:實例化全部的bean 以前,實例化並調用一些 context 內部持有的 BeanFactoryPostProcessor。

第21行registerBeanPostProcessors方法:

1protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
2   PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
3}
複製代碼

註冊全部的 bean 後期處理類。

第24行 initMessageSource 方法:

 1protected void initMessageSource() {
2   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
3   if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
4      this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
5      // Make MessageSource aware of parent MessageSource.
6      if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
7         HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
8         if (hms.getParentMessageSource() == null) {
9            // Only set parent context as parent MessageSource if no parent MessageSource
10            // registered already.
11            hms.setParentMessageSource(getInternalParentMessageSource());
12         }
13      }
14      if (logger.isTraceEnabled()) {
15         logger.trace("Using MessageSource [" + this.messageSource + "]");
16      }
17   }
18   else {
19      // Use empty MessageSource to be able to accept getMessage calls.
20      DelegatingMessageSource dms = new DelegatingMessageSource();
21      dms.setParentMessageSource(getInternalParentMessageSource());
22      this.messageSource = dms;
23      beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
24      if (logger.isTraceEnabled()) {
25         logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
26      }
27   }
28}
複製代碼

該方法進行了兩方面的處理:

若是此 context中的 beanFactory 有 MessageSource 屬性,則直接獲取其值,並將其父MessageSource 設置到此context 的父context中;

若是此 context 中的 beanFactory 沒有 MessageSource 屬性,則直接使用 parent context中的 MessageSource。

第27行initApplicationEventMulticaster:

 1protected void initApplicationEventMulticaster() {
2   ConfigurableListableBeanFactory beanFactory = getBeanFactory();
3   if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
4      this.applicationEventMulticaster =
5            beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
6   //去掉日誌打印
7   else {
8      this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
9      beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
10      //去掉日誌打印
11      }
12   }
13}
複製代碼

此方法初始化 ApplicationEventMulticaster 廣播器。

若是本地 context中有該屬性,則直接獲取值,若是沒有則構造一個默認的SimpleApplicationEventMulticaster。

第30行 onRefresh 方法:

1protected void onRefresh() throws BeansException {
2   // For subclasses: do nothing by default.
3}
複製代碼

又是一個模板方法,留待子類去實現。

主要是增長一些特定context 的 refresh 工做,在一些特殊的 bean 初始化時調用,該調用在任何單例對象實例化以前。

第33行registerListeners,檢出並註冊全部實現了ApplicationListener的監聽器,若是此時有 event,則分發之。

 1protected void registerListeners() {
2   // Register statically specified listeners first.
3   for (ApplicationListener<?> listener : getApplicationListeners()) {
4      getApplicationEventMulticaster().addApplicationListener(listener);
5   }
6
7   // Do not initialize FactoryBeans here: We need to leave all regular beans
8   // uninitialized to let post-processors apply to them!
9   String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.classtruefalse);
10   for (String listenerBeanName : listenerBeanNames) {
11      getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
12   }
13
14   // Publish early application events now that we finally have a multicaster...
15   Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
16   this.earlyApplicationEvents = null;
17   if (earlyEventsToProcess != null) {
18      for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
19         getApplicationEventMulticaster().multicastEvent(earlyEvent);
20      }
21   }
22}
複製代碼

第36行finishBeanFactoryInitialization方法:

完成此 context 中全部 factory bean 的初始化工做,實例化剩下的非惰性加載單例對象

 1protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
2   // Initialize conversion service for this context.
3   if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
4         beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
5      beanFactory.setConversionService(
6            beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
7   }
8
9   // Register a default embedded value resolver if no bean post-processor
10   // (such as a PropertyPlaceholderConfigurer bean) registered any before:
11   // at this point, primarily for resolution in annotation attribute values.
12   if (!beanFactory.hasEmbeddedValueResolver()) {
13      beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
14   }
15
16   // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
17   String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.classfalsefalse);
18   for (String weaverAwareName : weaverAwareNames) {
19      getBean(weaverAwareName);
20   }
21
22   // Stop using the temporary ClassLoader for type matching.
23   beanFactory.setTempClassLoader(null);
24
25   // Allow for caching all bean definition metadata, not expecting further changes.
26   beanFactory.freezeConfiguration();
27
28   // Instantiate all remaining (non-lazy-init) singletons.
29   beanFactory.preInstantiateSingletons();
30}
複製代碼

重點放在下面兩行上:

1// Allow for caching all bean definition metadata, not expecting further changes.
2beanFactory.freezeConfiguration();
3
4// Instantiate all remaining (non-lazy-init) singletons.
5beanFactory.preInstantiateSingletons();
複製代碼

第一步 freeze 全部的 bean定義數據,該定義不能被更改;

第二步 開始真正實例化全部的單例。

第39行finishRefresh方法:

 1protected void finishRefresh() {
2   // Clear context-level resource caches (such as ASM metadata from scanning).
3   clearResourceCaches();
4
5   // Initialize lifecycle processor for this context.
6   initLifecycleProcessor();
7
8   // Propagate refresh to lifecycle processor first.
9   getLifecycleProcessor().onRefresh();
10
11   // Publish the final event.
12   publishEvent(new ContextRefreshedEvent(this));
13
14   // Participate in LiveBeansView MBean, if active.
15   LiveBeansView.registerApplicationContext(this);
16}
複製代碼

此時正式宣告完成 context 的refresh 工做,調用 LifecycleProcessor 的 onRefresh 方法,以後發佈 ContextRefreshEvent 事件。

總結

此文對 Spring 中的幾個重要的 context 進行了分析,尤爲是對 AbstractApplicationContext 的主要脈絡進行了梳理。

相關文章
相關標籤/搜索