Spring 中的 context

BeanFactory

首先看下,官方在代码中给出的注释:

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

是接触所有Spring bean容器的根接口,这个接口被持有大量bean定义的对象实现。

从其接口中定义的方法即可看出,其为bean容器的真正含义。

ListableBeanFactory 继承了 BeanFactory,为其提供了枚举所有 beans 的方法:

ApplicationContext

而 ApplicationContext 类通过对该接口的扩展,提供了为application提供配置的扩展接口。

根据官方给出的注释,其总共功能有以下几点:

  1. 对应用的 component 的工厂方法;
  2. 一种通用的加载资源文件的方式;
  3. 对注册的监听器发布事件的能力;
  4. 解析message,支持国家化的能力。

这些能力主要通过继承各种接口获得,其自身接口主要扩展的重要方法主要有一个:

1@Nullable2ApplicationContext getParent();

在 SpringBoot 中,context 有其继承体系:每个不同的 servlet 都有自己独立的 context,而整个 application 有一个根 context,这个 context 是所有 servlet 所共享的

所以此处提供了获得父 context 的能力。

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 singletons5 * if it fails, to avoid dangling resources. In other words, after invocation6 * of that method, either all or no singletons at all should be instantiated.7 * @throws BeansException if the bean factory could not be initialized8 * @throws IllegalStateException if already initialized and multiple refresh9 * attempts are not supported10 */11void refresh() throws BeansException, IllegalStateException;

从注释中我们可以看到该方法的作用:

加载或者刷新持久层的配置资源,比如 xml、property 或者数据库文件。

因为该方法在应用启动时调用,所以如果失败,则要销毁掉所有已经创建好的单例对象。

换句话说就是:一旦该方法被调用,要么创建好所有的单例对象,要么一个单例对象都不会创建

AbstractApplicationContext

对于 ConfigurableApplicationContext,该抽象类提供了大部分的模板实现方法。

这里重点看下 refresh 方法:

1@Override2public void refresh() throws BeansException, IllegalStateException{3   synchronized (this.startupShutdownMonitor) {4      // Prepare this context for refreshing.5      prepareRefresh();67      // Tell the subclass to refresh the internal bean factory.8      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();910      // Prepare the bean factory for use in this context.11      prepareBeanFactory(beanFactory);1213      try {14         // Allows post-processing of the bean factory in context subclasses.15         postProcessBeanFactory(beanFactory);1617         // Invoke factory processors registered as beans in the context.18         invokeBeanFactoryPostProcessors(beanFactory);1920         // Register bean processors that intercept bean creation.21         registerBeanPostProcessors(beanFactory);2223         // Initialize message source for this context.24         initMessageSource();2526         // Initialize event multicaster for this context.27         initApplicationEventMulticaster();2829         // Initialize other special beans in specific context subclasses.30         onRefresh();3132         // Check for listener beans and register them.33         registerListeners();3435         // Instantiate all remaining (non-lazy-init) singletons.36         finishBeanFactoryInitialization(beanFactory);3738         // Last step: publish corresponding event.39         finishRefresh();40      }4142      catch (BeansException ex) {43         if (logger.isWarnEnabled()) {44            logger.warn("Exception encountered during context initialization - " +45                  "cancelling refresh attempt: " + ex);46         }4748         // Destroy already created singletons to avoid dangling resources.49         destroyBeans();5051         // Reset 'active' flag.52         cancelRefresh(ex);5354         // Propagate exception to caller.55         throw ex;56      }5758      finally {59         // Reset common introspection caches in Spring's core, since we60         // 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);67   // 初始化一些 environment 中的占位符属性8   initPropertySources();910   // 校验一些标记为 required 的必要属性11   getEnvironment().validateRequiredProperties();1213   // 存储“准备刷新”的一些监听器.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   }2223   // 存储事件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@Override8public 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()));89   // Configure the bean factory with context callbacks.10   // 设置一些用于 bean 后期处理的 processor11   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);1920   // 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.class, this);25   beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);26   beanFactory.registerResolvableDependency(ApplicationContext.class, this);2728   // 注册该监听器用于检测监听器 bean29   beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));3031   // 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   }3738   // 注册默认的 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());34   // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime5   // (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 MessageSource10            // 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   }67   // Do not initialize FactoryBeans here: We need to leave all regular beans8   // uninitialized to let post-processors apply to them!9   String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);10   for (String listenerBeanName : listenerBeanNames) {11      getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);12   }1314   // 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   }89   // Register a default embedded value resolver if no bean post-processor10   // (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   }1516   // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.17   String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);18   for (String weaverAwareName : weaverAwareNames) {19      getBean(weaverAwareName);20   }2122   // Stop using the temporary ClassLoader for type matching.23   beanFactory.setTempClassLoader(null);2425   // Allow for caching all bean definition metadata, not expecting further changes.26   beanFactory.freezeConfiguration();2728   // 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();34// 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();45   // Initialize lifecycle processor for this context.6   initLifecycleProcessor();78   // Propagate refresh to lifecycle processor first.9   getLifecycleProcessor().onRefresh();1011   // Publish the final event.12   publishEvent(new ContextRefreshedEvent(this));1314   // Participate in LiveBeansView MBean, if active.15   LiveBeansView.registerApplicationContext(this);16}

此时正式宣告完成 context 的refresh 工作,调用 LifecycleProcessor 的 onRefresh 方法,之后发布 ContextRefreshEvent 事件。

总结

此文对 Spring 中的几个重要的 context 进行了分析,尤其是对 AbstractApplicationContext 的主要脉络进行了梳理。

转载于:https://juejin.im/post/5cd182d36fb9a03222793435

Spring 中的 context相关推荐

  1. 关于Spring中的context:annotation-config/配置(开启注解)

    转自:https://www.cnblogs.com/doudouxiaoye/p/5681518.html 当我们需要使用BeanPostProcessor时,直接在Spring配置文件中定义这些B ...

  2. spring中的context:include-filter和context:exclude-filter的区别

    http://blog.csdn.net/w2393040183/article/details/50749851 <!-- 扫描@Controller注解 --><context: ...

  3. Spring加载context的几种方法

    Spring中的context管理 Spring中IOC容器的初始化: ApplicationContext即是保存bean对象的容器,故容器本身的初始化,就是通过一系列的配置,将Applicatio ...

  4. spring中context:property-placeholder标签详解

    spring中context:property-placeholder标签的使用说明 1,有些参数在某些阶段中是常量. 在开发阶段我们连接数据库时的url,username,password等信息 分 ...

  5. spring中context:property-placeholder/元素

    1.有些参数在某些阶段中是常量 比如 :a.在开发阶段我们连接数据库时的连接url,username,password,driverClass等 b.分布式应用中client端访问server端所用的 ...

  6. Spring中配置DataSource数据源的几种选择

    Spring中配置DataSource数据源的几种选择 在Spring框架中有如下3种获得DataSource对象的方法: 从JNDI获得DataSource. 从第三方的连接池获得DataSourc ...

  7. Spring中WebApplicationContext

    ApplicationContext是Spring的核心,Context我们通常解释为上下文环境,我想用"容器"来表述它更容易理解一 些,ApplicationContext则是& ...

  8. Spring中使用Schedule调度

    在spring中两种办法使用调度,以下使用是在spring4.0中. 一.基于application配置文件,配置入下: 1 <bean id="jobDetail" cla ...

  9. Spring中SmartLifecycle和Lifecycle的作用和区别

    欢迎关注方志朋的博客,回复"666"获面试宝典 本文基于SpringBoot 2.5.0-M2讲解Spring中Lifecycle和SmartLifecycle的作用和区别,以及如 ...

最新文章

  1. PC行业为何需要华为们被搅局?
  2. selenium RC 环境配置
  3. 深度学习核心技术精讲100篇(四十四)-深度召回在招聘推荐中的挑战和实践
  4. java(4)——数据类型中的数值型的浮点数
  5. php中读取文件函数,php 读取文件夹与文件夹中文件的函数
  6. java中factory方法_Java的23中设计模式--工厂方法模式(Factory Method)
  7. 47 MM配置-采购-条件-定价过程-定义方案确认
  8. Nacos Spring 快速开始
  9. python新特性_Python3.6正式版新特性预览
  10. flask-sqlalchemy 数据基本操作--实例
  11. 金山云肖江:5G推动智慧人居产业到达新高度
  12. css设置table阴影浮动效果
  13. 【编程软件】keli烧录代码点击Download或者Debug界面卡死
  14. [转] Ubuntu 16.04 RTL8111/8168/8411 不能上网 经常断网解决办法
  15. aso关键词优化,我们该不该去做?
  16. 用html怎样实现抽奖效果,html5+css3实现抽奖活动的效果
  17. 重启防火墙(iptables)命令#service iptable restart失效
  18. 神经网络传递函数的选择,卷积神经网络风格迁移
  19. (JAVA练习)输入一个四位数,各个位的数字相加
  20. 【PyTorch】提高mnist模型精确度

热门文章

  1. 用脑电波玩游戏,这款VR体验逆天了
  2. 特殊的Windows消息
  3. Save could not be completed. Eclipse国际化的问题解决
  4. 使用XML创建Excel文档
  5. 使用Cloudera Manager部署oozie
  6. 跟我学雨林木风系统制作——2.涉及的技术及用到的工具介绍
  7. debian+pxe+preseed.cfg 安装配置
  8. POJ 1035, Spell checker
  9. C++调用matlab char16_t 重复定义
  10. 正则表达式:元字符,量词