Spring WebFlux 工作原理分析 - 2.应用启动过程--3.更新应用上下文

在该系列上一篇文章中,我们分析了应用上下文准备,创建和初始化的过程,这一篇文章我们来分析应用启动的最后一个主要步骤:SpringApplication#refreshContext,更新应用上下文:

// SpringApplication 代码片段
	private void refreshContext(ConfigurableApplicationContext context) {
		refresh(context);
		if (this.registerShutdownHook) {
			try {
				context.registerShutdownHook();
			}
			catch (AccessControlException ex) {
				// Not allowed in some environments.
			}
		}
	}
	protected void refresh(ApplicationContext applicationContext) {
		Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
		((AbstractApplicationContext) applicationContext).refresh();
	}    

从以上代码实现来看,SpringApplication#refreshContext最终会调用ApplicationContext对象自身的refresh方法来完成应用上下文对象的更新。结合本系列文章中的例子和以上各篇文章的分析,我们知道这里的ApplicationContext对象实现类为AnnotationConfigReactiveWebServerApplicationContext,我们从其refresh方法开始分析。实际上,类AnnotationConfigReactiveWebServerApplicationContext自身并未定义refresh方法,因为它继承自ReactiveWebServerApplicationContext,所以当调用AnnotationConfigReactiveWebServerApplicationContext#refresh时,其实真正被调用的方法就是ReactiveWebServerApplicationContext#refresh

1. ReactiveWebServerApplicationContext#refresh

	@Override
	public final void refresh() throws BeansException, IllegalStateException {
		try {
           // 调用基类的 refresh 方法,
           // 基类是 AbstractApplicationContext
			super.refresh();
		}
		catch (RuntimeException ex) {
          // 如果出现运行时异常,则停止 Reactive Web Server 并释放有关资源
			stopAndReleaseReactiveWebServer();
          // 继续抛出异常  
			throw ex;
		}
	}

ReactiveWebServerApplicationContext#refresh实现来看,它主要是调用基类AbstractApplicationContext#refresh方法,如果基类refresh出现运行时异常,则调用#stopAndReleaseReactiveWebServer停止和释放Reactive Web Server,然后继续抛出异常。从这段逻辑我们可以推测出,AbstractApplicationContext#refresh逻辑运行过程中一定出现类Reactive Web Server启动的过程。我们继续分析。

2. AbstractApplicationContext#refresh

	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
           // 更新之前的准备工作 :
           // 1. 设定启动时间
           // 2. 设置应用上下文状态为活跃
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
           // 应用上下文的核心可以认为就是一个Spring IoC 容器,也就是一般所所说的
           // bean 容器, bean 工厂, 这里获得该容器对象
          // 该 bean 容器对象其实早在应用上下文对象构造函数中就被创建,
          // 这一点可以参考当前应用上下文的基类 GenericApplicationContext
          // 的无参构造函数 : this.beanFactory = new DefaultListableBeanFactory()
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
          // 准备 bean 工厂 :
          // 1. 设置 bean 类加载器为当前应用上下文所使用的类加载器
          // 2. 设置 bean 表达式解析器为一个新建的 StandardBeanExpressionResolver 对象
          // 3. 为 bean 工厂添加一个 PropertyEditorRegistrar : ResourceEditorRegistrar,
          //   关联到当前应用上下文和当前环境信息对象
          // 4. 为 bean 工厂添加一个 BeanPostProcessor : ApplicationContextAwareProcessor,
          //   关联到当前应用上下文
          // 5. 将一些类型/接口排除在依赖注入机制之外 
          //    比如 : EnvironmentAware,EmbeddedValueResolverAware,
          //    ResourceLoaderAware,ApplicationEventPublisherAware,
          //   MessageSourceAware,ApplicationContextAware
          // 6. 将一些排除在依赖注入机制外的类型/接口关联到特定的bean组件
          //   比如 :
          //   BeanFactory 类关联到当前beanFactory对象
          //   ResourceLoader 类关联到当前应用上下文对象
          //  ApplicationEventPublisher 类关联到当前应用上下文对象
          //  ApplicationContext 类关联到当前应用上下文对象
          // 7. 为 bean 工厂添加一个 BeanPostProcessor : ApplicationListenerDetector,
          // 8.如果以下 bean 注册不存在于 bean 工厂中,则将它们作为单例bean注册到 bean 工厂
          //    名称 : environment, 对象 : 当前环境信息对象, 类型 : ConfigurableEnvironment
          //    名称 : systemProperties, 对象 : 当前环境信息对象中的相应部分 , 类型 : Map<String, Object> 
          //    名称 : systemEnvironment, 对象 : 当前环境信息对象中的相应部分 , 类型 : Map<String, Object> 
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
              // 对 beanFactory 的后置处理,在该系列文章的例子项目中其实为空
              // AnnotationConfigReactiveWebServerApplicationContext
              // 对此方法有扩展实现,主要是会在这里扫描指定的包或者读取指定的
              // 被注解类,不过在该系列文章的例子项目中,这些属性都没有被指定,
              //所以该方法这里实际上退化为空
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
              // 当前应用上下文对象创建之后的准备阶段,会被调用者通过一些
              // ApplicationContextInitializer 来初始化, 比如在该系列文章的例子
              // 项目中,SpringApplication#prepareContext 方法中就会调用
              // SpringApplication#applyInitializers 来应用一些 ApplicationContextInitializer,
              // 这些 ApplicationContextInitializer 中有些会往当前应用上下文中
              // 添加一些 BeanFactoryPostProcessor, 一般它们是如下三个 :
              // 0 : SharedMetadataReaderFactoryContextInitializer$CachingMetadataReaderFactoryPostProcessor
              // 1 : ConfigurationWarningsApplicationContextInitializer$ConfigurationWarningsPostProcessor
              // 2 : ConfigFileApplicationListener$PropertySourceOrderingPostProcessor
              // 另外通过bean注册,beanFactory 可能也会存在一些其他的 BeanFactoryPostProcessor,
              // 他们都会在这里被调用
              // 这里更多的执行细节,可以参考 : 
              // PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors
              // 这里不做更多展开
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
              // 在 Spring bean 容器中,BeanPostProcessor 是用来拦截 bean 的创建的,
              // BeanPostProcessor 也可以通过类似注册普通业务bean的方式注册到
              // Spring bean 容器,所以它们在 Spring bean 容器中跟普通业务bean
              // 在这一点上有着相同的存在方式,不过 Spring bean 另外维护了一个
              // beanPostProcessors 列表属性,用来记录容器中所有的 BeanPostProcessor
              // bean 实例。这里 registerBeanPostProcessors 方法的功能就是
              // Spring bena 容器中识别出所有类型为 BeanPostProcessor 的 bean
              // (这时就像访问一个普通bean一样),然后将它们都添加到 beanPostProcessors
              // 属性列表特殊管理起来,用于所有拦截其他业务 bean 的创建
              // 这里更多的执行细节,可以参考 : 
              // PostProcessorRegistrationDelegate#registerBeanPostProcessors  
              // 这里不做更多展开
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
              // 初始化消息源  
				initMessageSource();

				// Initialize event multicaster for this context.
              // 初始化应用事件多播器,Spring 应用的事件机制的初始化动作,
              // 如果容器中没有定义名称为 applicationEventMulticaster 的 bean 组件,
              // 则这里会定义一个,实现类使用 SimpleApplicationEventMulticaster,
              // 这也是缺省情况。
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
              //  AbstractApplicationContext 虽然定义了该方法,但其实现为空,
              // 该方法是专门留给子类提供实现的,其设计目的是在容器实例化单例bean之前,
              // 对一些特殊的 bean 做初始化,
              // 当前应用上下文对象的实际类型是 AnnotationConfigReactiveWebServerApplicationContext,
              // 在其基类 ReactiveWebServerApplicationContext (AbstractApplicationContext的子类)
              // 中对该方法做了定制实现,我们下一小节会专门分析其代码。
				onRefresh();

				// Check for listener beans and register them.
              // 以上的执行逻辑中可能会往当前应用上下文对象增加一些 ApplicationListener,
              // 它们都记在 this.applicationListeners 属性中,另外 bean 容器中也会存在一些
              // 通过 bean 定义注册形式进入的 ApplicationListener,所有这些 ApplicationListener,
              // 在这里都会被添加到之前所创建的应用事件多播器
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
              // 锁定bean定义信息,实例化所有没有被定义为懒加载的单例bean  
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
              // 完成上下文更新,这是上下文更新的最后一步,该步骤在  AbstractApplicationContext
              // 基类中的缺省实现是 :
              // 1. 清空当前应用上下文从创建,初始化到刷新过程中所使用的缓存,比如扫描过程中
              //    所产生的 ASM 元数据;
              // 2. 初始化生命周期处理器 , 其实是向bean容器注册了一个单例bean :
              //   名称 : lifecycleProcessor , 实现类 : DefaultLifecycleProcessor,
              // 3. 调用 lifecycleProcessor bean 的 onRefresh 方法,启用容器中所有
              //   实现了 Lifecycle 接口的bean(当然不包括lifecycleProcessor bean 自身,
              //   虽然它也实现了 Lifecycle 接口)
              // 4. 发布事件 ContextRefreshedEvent , 上面我们已经提到了应用事件多播器,
              // 这里其实就是通过应用事件多播器将事件广播到管理到它上面的各个事件监听器
              // 而对当前应用上下文实现类对其做了扩展,增加了启动 Web Server 以及发布
              // 相应事件的步骤,接下来小节中,我们会继续对此进行分析。
				finishRefresh();
			}

			catch (BeansException ex) {
              // 出现 BeansException 异常的情况
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
              // 销毁所有已经创建的单例bean,避免资源悬挂  
				destroyBeans();

				// Reset 'active' flag.
              // 将当前应用上下文对象标记为不活跃  
				cancelRefresh(ex);

				// Propagate exception to caller.
              // 继续抛出异常  
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
              // 不过应用上下文对象更新过程是否出错都会执行的动作 :
              // 1. 反射工具缓存清除
              // 2. 注解工具缓存清除
              // 3. 类型解析工具缓存清除
              // 4. Java类的JavaBean信息缓存清除
				resetCommonCaches();
			}
		}
	}

从上面的代码实现和分析可见,AbstractApplicationContext#refresh对所有子类规定了相同的应用上下文更新流程,而具体到ReactiveWebServerApplicationContext这种具体实现,以上流程的主要差异在于ReactiveWebServerApplicationContext对于其中部分流程逻辑的覆盖定制 :

  1. onRefresh – 增加了创建 Reactive Web Server的步骤
  2. finishRefresh – 增加了启动 Reactive Web Server的步骤

接下来,我们着重来看这两个方法的实现。

2.1 ReactiveWebServerApplicationContext#onRefresh

	@Override
	protected void onRefresh() {
       // 调用基类的缺省实现
		super.onRefresh();
		try {
           // 创建 Reactive Web 服务器
			createWebServer();
		}
		catch (Throwable ex) {
			throw new ApplicationContextException("Unable to start reactive web server", ex);
		}
	}

2.2 ReactiveWebServerApplicationContext#finishRefresh

	@Override
	protected void finishRefresh() {
       // 调用基类的缺省实现
		super.finishRefresh();
        
       // 启动 Reactive Web 服务器 
		WebServer webServer = startReactiveWebServer();
		if (webServer != null) {
          // 如果 Reactive Web 服务器启动成功,发布事件 : ReactiveWebServerInitializedEvent
			publishEvent(new ReactiveWebServerInitializedEvent(webServer, this));
		}
	}

总结

从本文的分析来看,一个Spring WebFlux的应用上下文AnnotationConfigReactiveWebServerApplicationContext的更新跟其他实现类的更新流程并无不同,都是AbstractApplicationContext#refresh,而其中不同之处在于,AnnotationConfigReactiveWebServerApplicationContext的基类ReactiveWebServerApplicationContext针对Reactive Web环境针对部分流程逻辑的覆盖实现,具体来讲,如下 :

  1. onRefresh方法在缺省流程逻辑后扩展增加了创建Web服务器逻辑createWebServer
  2. finishRefresh方法在缺省流程逻辑后扩展增加了启动Web服务器逻辑startReactiveWebServer
  3. refresh方法首先执行缺省更新流程,中间包括被定制了的逻辑:onRefreshfinishRefresh,如果整个缺省流程出现运行时异常,它会调用stopAndReleaseReactiveWebServer试图停止和释放Web服务器。

实际上,当定制化的应用上下文对象AnnotationConfigReactiveWebServerApplicationContext更新完成时,如果没有异常,整个Web服务器就处于可以接收和处理用户请求的状态了。按说我们接下来可以开始分析WebFlux环境中一个请求的处理过程。不过,对于Web服务器创建和启动过程,我们还没有足够的了解。试想一下,如果对具体的工作组件是怎样被组装到一起的都不了解,我们又怎么能够理解它内部是如何处理一个请求的呢?所以接下来的篇幅,我们将先分析WebFlux环境中Web服务器的创建和启动。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值