Spring WebFlux 工作原理分析 - 2.应用启动过程--4.创建Web服务器

本文解析了在Spring Boot应用中,如何通过ReactiveWebServerApplicationContext创建Web服务器的过程,涉及ServerManager类的使用,以及ReactiveWebServerFactoryAutoConfiguration自动配置机制。
部署运行你感兴趣的模型镜像

上篇文章我们分析了整个应用上下文的更新过程,但是,我们对AnnotationConfigReactiveWebServerApplicationContext应用上下文中跟当前Web环境紧密相关的两个环节还不是很了解,它们分别是:

  1. onRefresh方法在缺省流程逻辑后扩展增加的Web服务器创建逻辑:createWebServer
  2. finishRefresh方法在缺省流程逻辑后扩展增加的Web服务器启动逻辑:startReactiveWebServer

这一篇文章,我们专门来讲解onRefresh中的createWebServer,也就是创建Web服务器的过程逻辑。

首先,我们看应用上下文的方法onRefresh,它实现在基类ReactiveWebServerApplicationContext中:

	// ReactiveWebServerApplicationContext 代码片段
    @Override
	protected void onRefresh() {
        // 调用基类缺省的 onRefresh 逻辑,其实为空
		super.onRefresh();
        
       // 尝试创建Web服务器 
		try {
			createWebServer();
		}
		catch (Throwable ex) {
			throw new ApplicationContextException("Unable to start reactive web server", ex);
		}
	}

上面代码中所调用的方法createWebServer实现如下,也实现在基类ReactiveWebServerApplicationContext中:

	// ReactiveWebServerApplicationContext 代码片段
    private void createWebServer() {
      // this.serverManager 变量用来记录一个 ServerManager 对象,
      // ServerManager 是 ReactiveWebServerApplicationContext 的内嵌类,      
      // 一个 ServerManager 对象用来管理一个 Reactive Web Server 和相应的
      // HttpHandler,可以理解 ServerManager 是一个包装器,每个 ServerManager 
      // 包含了一个 WebServer 和一个 HttpHandler 。
      // 在应用启动过程中,当前应用上下文对象更新过程中, this.serverManager
      // 初始值为 null,正是在该方法 createWebServer 中将其设置为所创建的
      // Reactive Web Server 。
		ServerManager serverManager = this.serverManager;
		if (serverManager == null) {
           // 这里创建一个 ServerManager 对象,记录到  this.serverManager
           // ServerManager 对象所包含的 :
           // 1. WebServer server 通过 getWebServerFactory() 所获取的工厂方法创建
           // 2. HttpHandler handler 初始化为一个初始 handler (调用的话会直接抛异常)
			this.serverManager = ServerManager.get(getWebServerFactory());
		}
       
       // 初始化属性源,缺省实现为空,子类对该方法也没有定制实现       
		initPropertySources();
	}

上面createWebServer方法中有两个要点需要详细分析一下。一个是ServerManager类自身,因为它包装了所创建的Web服务器,所以值得一提。另外一个是getWebServerFactory方法,使用它用来获取Web服务器的工厂方法,我们有必要分析它为创建Web服务器都提供了什么。

1. ServerManager

首先我们来看ServerManager类,它是一个ReactiveWebServerApplicationContext内嵌类,代码如下 :

// ReactiveWebServerApplicationContext 代码片段
    /**
	 * Internal class used to manage the server and the {@link HttpHandler}, taking care
	 * not to initialize the handler too early.
	 */
   // 实现了接口 HttpHandler
	static final class ServerManager implements HttpHandler {

		private final WebServer server;

		private volatile HttpHandler handler;


       // 使用指定 ReactiveWebServerFactory factory 构建  WebServer this.server
       // this.handler 初始化为当前对象的方法 handleUninitialized, 该方法被调用的话
       // 会直接抛出异常,它只是用来作为当前对象尚未完全初始化之前的占位符,并不是
       // 设计给调用者使用的,调用者随后调用 ServerManager.start 启动一个 Web
       // 服务器时,需要提供自己的 HttpHandler 设置给被启动的 ServerManager
       // 对象的属性 handler 上
		private ServerManager(ReactiveWebServerFactory factory) {
			this.handler = this::handleUninitialized;
			// 注意这里创建 WebServer 所传递的参数 HttpHandler
			// 是当前 ServerManager 实例
			this.server = factory.getWebServer(this);
		}


        // 一个可以赋值给 HttpHandler 类型函数式接口的函数
       // 该方法被调用的话 会直接抛出异常,它只是用来作为当前对象尚未完全初始化之前的占位符,
       // 并不是设计给调用者使用的
		private Mono<Void> handleUninitialized(ServerHttpRequest request, ServerHttpResponse response) {
			throw new IllegalStateException("The HttpHandler has not yet been initialized");
		}

       // 所实现接口 HttpHandler 约定的方法,处理请求写回响应,具体调用委托给了所包含的 this.handler 
		@Override
		public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
			return this.handler.handle(request, response);
		}

		public HttpHandler getHandler() {
			return this.handler;
		}

       // 静态工具方法 : 使用指定的 ReactiveWebServerFactory 构建 ServerManager 对象,
		public static ServerManager get(ReactiveWebServerFactory factory) {
			return new ServerManager(factory);
		}

       // 静态工具方法 : 获取指定 ServerManager 对象的的 WebServer server 属性
		public static WebServer getWebServer(ServerManager manager) {
			return (manager != null) ? manager.server : null;
		}

       // 静态工具方法 : 启动指定的 ServerManager 所包含的 Web 服务器,
       // 使用的 HttpHandler 使用 handlerSupplier 所提供的 HttpHandler
		public static void start(ServerManager manager, Supplier<HttpHandler> handlerSupplier) {
			if (manager != null && manager.server != null) {
				manager.handler = handlerSupplier.get();
				manager.server.start();
			}
		}

       // 静态工具方法  : 停止指定的 ServerManager 所包含的 Web 服务器, 
		public static void stop(ServerManager manager) {
			if (manager != null && manager.server != null) {
				try {
					manager.server.stop();
				}
				catch (Exception ex) {
					throw new IllegalStateException(ex);
				}
			}
		}

	}

从上面的分析可见,createWebServer创建了一个ServerManager,而该ServerManager包含两个信息:

  1. 一个通过指定的ReactiveWebServerFactory创建的WebServer
  2. 一个初始化为handleUninitializedHttpHandler,

不过此时所包含的HttpHandler被调用的话会直接抛出异常。实际上,它只是一个占位符,而并非留给调用者使用的,从ServerManager的静态工具方法start来看,稍后WebServer启动时,需要调用者从外部指定自己的HttpHandler以替换该缺省HttpHandler

在本系列文章的例子应用中,上面的ReactiveWebServerFactory其实是NettyReactiveWebServerFactory(至于为什么是NettyReactiveWebServerFactory,随后会有分析),通过它创建WebServer的过程如下 :

	// NettyReactiveWebServerFactory 代码片段
	@Override
	public WebServer getWebServer(HttpHandler httpHandler) {
		// 创建 HttpServer  httpServer, HttpServer 属于项目 reactor
		HttpServer httpServer = createHttpServer();
		// 包装成 NettyWebServer, WebServer 接口针对 Netty 的实现类, 是 Spring 对 reactor HttpServer
		// 的封装
		// 从上面的分析我们知道,参数 httpHandler 会是一个 ServerManager 实例,它实现了接口
		// HttpHandler , 并且包装一个 HttpHandler  实例,所被包装的这个 HttpHandler 实例
		// 才是最终处理请求的 HttpHandler。现在创建 WebServer 的过程中虽然使用的是一个 ServerManager
		// 实例,但最终处理请求的 HttpHandler 会使用 ServerManager 实例所包装的那个。 
		ReactorHttpHandlerAdapter handlerAdapter = new ReactorHttpHandlerAdapter(httpHandler);
		return new NettyWebServer(httpServer, handlerAdapter, this.lifecycleTimeout);
	}
	
	private HttpServer createHttpServer() {
		HttpServer server = HttpServer.create();
		// 设置服务器监听地址和端口
		if (this.resourceFactory != null) {
			LoopResources resources = this.resourceFactory.getLoopResources();
			Assert.notNull(resources, "No LoopResources: is ReactorResourceFactory not initialized yet?");
			server = server.tcpConfiguration(
					(tcpServer) -> tcpServer.runOn(resources).addressSupplier(this::getListenAddress));
		}
		else {
			server = server.tcpConfiguration((tcpServer) -> tcpServer.addressSupplier(this::getListenAddress));
		}
		// SSL 设置,HTTP2 设置
		if (getSsl() != null && getSsl().isEnabled()) {
			SslServerCustomizer sslServerCustomizer = new SslServerCustomizer(getSsl(), getHttp2(),
					getSslStoreProvider());
			server = sslServerCustomizer.apply(server);
		}
		// 压缩设置
		if (getCompression() != null && getCompression().getEnabled()) {
			CompressionCustomizer compressionCustomizer = new CompressionCustomizer(getCompression());
			server = compressionCustomizer.apply(server);
		}
		server = server.protocol(listProtocols()).forwarded(this.useForwardHeaders);
		return applyCustomizers(server);
	}

接下来,我们先不急于分析Web服务器的启动,而是看一下创建Web服务器的另外一个要点: 方法getWebServerFactory(),获取创建Web服务器的工厂对象。

2. ReactiveWebServerFactory getWebServerFactory()

方法getWebServerFactory代码实现如下 :

	// ReactiveWebServerApplicationContext 代码片段
    protected ReactiveWebServerFactory getWebServerFactory() {
		// Use bean names so that we don't consider the hierarchy
       // 从容器中获取类型为  ReactiveWebServerFactory 的所有 bean 的名称
		String[] beanNames = getBeanFactory().getBeanNamesForType(ReactiveWebServerFactory.class);
		if (beanNames.length == 0) {
          // 如果容器中不存在类型为 ReactiveWebServerFactory 的 bean,则直接抛出异常,
          // 换句话讲,容器中必须要通过某种方式已经注册了类型为 ReactiveWebServerFactory 的 bean
			throw new ApplicationContextException(
					"Unable to start ReactiveWebApplicationContext due to missing " 
					+ "ReactiveWebServerFactory bean.");
		}
		if (beanNames.length > 1) {
           // 如果容器中存在多个类型为 ReactiveWebServerFactory 的 bean,则也直接抛出异常,
          // 换句话讲,容器中必须要有且仅有一个类型为 ReactiveWebServerFactory 的 bean        
			throw new ApplicationContextException(
					"Unable to start ReactiveWebApplicationContext due to multiple "
					+ "ReactiveWebServerFactory beans : " 
					+ StringUtils.arrayToCommaDelimitedString(beanNames));
		}
        
       //  容器中有且仅有一个类型为 ReactiveWebServerFactory 的 bean  , 现在获取并返回它
		return getBeanFactory().getBean(beanNames[0], ReactiveWebServerFactory.class);
	}

方法getWebServerFactory的实现逻辑不难理解,它要求容器中有且仅有一个类型为ReactiveWebServerFactorybean。如果不是这样,则它会抛出异常;如果是这样,它会获取该ReactiveWebServerFactory bean供调用者用于创建相应的Web服务器。那么,问题来了,我们之前分析启动过程中并没有遇到过该ReactiveWebServerFactory bean的注册,但是getWebServerFactory方又确实能够发现容器中存在ReactiveWebServerFactory bean,这又是为什么呢 ? 这里,我们就不得不考虑Spring Boot的自动配置机制了。实际上,ReactiveWebServerFactory bean之所以存在,正是因为Spring Boot的自动配置机制ReactiveWebServerFactoryAutoConfiguration

3. ReactiveWebServerFactoryAutoConfiguration自动配置

package org.springframework.boot.autoconfigure.web.reactive;

// 省略 import 行

/**
 * {@link EnableAutoConfiguration Auto-configuration} for a reactive web server.
 *
 * @author Brian Clozel
 * @since 2.0.0
 */
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
// 仅在类 ReactiveHttpInputMessage 存在于 classpath 上时生效,
// 这是 spring-web 包内针对 Reactive Web 服务的一个接口类,
// 在我们的例子应用中,显然它是存在于 classpath 上的
@ConditionalOnClass(ReactiveHttpInputMessage.class)
// 仅在当前Web环境是 REACTIVE 时才生效,之前的分析可以表明,
// 我们的例子应用就是这种情况
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
// 将前缀为 server 的配置参数加载到类型为 ServerProperties 的bean
@EnableConfigurationProperties(ServerProperties.class)
// 1. 导入 BeanPostProcessorsRegistrar, BeanPostProcessorsRegistrar 是 ReactiveWebServerFactoryAutoConfiguration
// 内嵌定义的一个 ImportBeanDefinitionRegistrar, 它向容器注册一个 WebServerFactoryCustomizerBeanPostProcessor,
// WebServerFactoryCustomizerBeanPostProcessor 作为一个 BeanPostProcessor , 用于在 WebServerFactory 对象创建时
// 将容器中所有的 WebServerFactoryCustomizer 应用到 WebServerFactory bean 对象
// 2. 导入 ReactiveWebServerFactoryConfiguration 配置中定义的配置子类 EmbeddedTomcat, EmbeddedJetty,
//  EmbeddedUndertow,EmbeddedNetty。这4个配置子类会检测相应Web服务器实现的特征类,从而定义相应的
// ReactiveWebServerFactory 到容器。这就是我们上面分析中提到的创建Web服务器所需要的 ReactiveWebServerFactory bean。
// 在本系列文章的例子应用中,其实这4个配置中生效的只有 EmbeddedNetty,相应的 ReactiveWebServerFactory bean
// 实现类实际为 NettyReactiveWebServerFactory
@Import({ ReactiveWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
		ReactiveWebServerFactoryConfiguration.EmbeddedTomcat.class,
		ReactiveWebServerFactoryConfiguration.EmbeddedJetty.class,
		ReactiveWebServerFactoryConfiguration.EmbeddedUndertow.class,
		ReactiveWebServerFactoryConfiguration.EmbeddedNetty.class })
public class ReactiveWebServerFactoryAutoConfiguration {

    // 注册一个 ReactiveWebServerFactoryCustomizer bean 到容器,
    // 该 ReactiveWebServerFactoryCustomizer bean 其实是将配置参数设置到 ReactiveWebServerFactory bean 上,
    // 它会被 BeanPostProcessorsRegistrar 所注册的 BeanPostProcessor WebServerFactoryCustomizerBeanPostProcessor
    // 使用,具体应用点在 ReactiveWebServerFactory bean 创建时
	@Bean
	public ReactiveWebServerFactoryCustomizer reactiveWebServerFactoryCustomizer(
			ServerProperties serverProperties) {
		return new ReactiveWebServerFactoryCustomizer(serverProperties);
	}

	/**
	 * Registers a {@link WebServerFactoryCustomizerBeanPostProcessor}. Registered via
	 * {@link ImportBeanDefinitionRegistrar} for early registration.
	 */
	public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, 
						BeanFactoryAware {

		private ConfigurableListableBeanFactory beanFactory;

		@Override
		public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
			if (beanFactory instanceof ConfigurableListableBeanFactory) {
				this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
			}
		}

		@Override
		public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
				BeanDefinitionRegistry registry) {
			if (this.beanFactory == null) {
				return;
			}
			registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor",
					WebServerFactoryCustomizerBeanPostProcessor.class);
		}

		private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, 
					String name, Class<?> beanClass) {
			if (ObjectUtils.isEmpty(
				this.beanFactory.getBeanNamesForType(beanClass, true, false))) {
				RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
				beanDefinition.setSynthetic(true);
				registry.registerBeanDefinition(name, beanDefinition);
			}
		}

	}

}

从上面分析可见,ReactiveWebServerFactoryAutoConfiguration自动配置类在条件满足时做了如下事情 :

  1. 将前缀为 server 的配置参数加载到类型为 ServerPropertiesbean
  2. 定义一个bean ReactiveWebServerFactoryCustomizer,该bean的作用时应用于某个WebServerFactory bean,将ServerProperties 参数(实际上是上面提到的ServerProperties bean)中的参数设置到WebServerFactory bean;这些信息包括: 端口号参数,主机地址参数,SSL配置参数,压缩参数,HTTP2启用参数;
  3. 导入 BeanPostProcessorsRegistrar,进而向容器注册BeanPostProcessor WebServerFactoryCustomizerBeanPostProcessor,该BeanPostProcessor用于在 WebServerFactory 对象创建时将容器中所有的 WebServerFactoryCustomizer 应用到 WebServerFactory bean ;
  4. 导入 ReactiveWebServerFactoryConfiguration 自身定义的配置子类 EmbeddedTomcat, EmbeddedJetty,EmbeddedUndertow,EmbeddedNetty。这4个配置子类会检测相应Web服务器实现的特征类,从而定义相应的ReactiveWebServerFactory 到容器。这就是我们上面分析中提到的创建Web服务器所需要的 ReactiveWebServerFactory bean。在本系列文章的例子应用中,其实这4个配置中生效的只有EmbeddedNetty,相应的ReactiveWebServerFactory bean实现类实际为 NettyReactiveWebServerFactory,相应地,它最终所创建WebServer实现类使用NettyWebServer

下面,给出ReactiveWebServerFactoryConfiguration的源代码,它包含了以上提到的4个配置子类供参考:

package org.springframework.boot.autoconfigure.web.reactive;

// 省略 import 行


abstract class ReactiveWebServerFactoryConfiguration {

	// 在 reactor.netty.http.server.HttpServer 存在于 classpath 时生效
	// 定义 bean :
	// 1. ReactorResourceFactory reactorServerResourceFactory
	// 2. NettyReactiveWebServerFactory nettyReactiveWebServerFactory
	@Configuration
	@ConditionalOnMissingBean(ReactiveWebServerFactory.class)
	@ConditionalOnClass({ HttpServer.class })
	static class EmbeddedNetty {

		@Bean
		@ConditionalOnMissingBean
		public ReactorResourceFactory reactorServerResourceFactory() {
			return new ReactorResourceFactory();
		}

		@Bean
		public NettyReactiveWebServerFactory nettyReactiveWebServerFactory(
												ReactorResourceFactory resourceFactory) {
			NettyReactiveWebServerFactory serverFactory = new NettyReactiveWebServerFactory();
			serverFactory.setResourceFactory(resourceFactory);
			return serverFactory;
		}

	}

	@Configuration
	@ConditionalOnMissingBean(ReactiveWebServerFactory.class)
	@ConditionalOnClass({ org.apache.catalina.startup.Tomcat.class })
	static class EmbeddedTomcat {

		@Bean
		public TomcatReactiveWebServerFactory tomcatReactiveWebServerFactory() {
			return new TomcatReactiveWebServerFactory();
		}

	}

	@Configuration
	@ConditionalOnMissingBean(ReactiveWebServerFactory.class)
	@ConditionalOnClass({ org.eclipse.jetty.server.Server.class })
	static class EmbeddedJetty {

		@Bean
		@ConditionalOnMissingBean
		public JettyResourceFactory jettyServerResourceFactory() {
			return new JettyResourceFactory();
		}

		@Bean
		public JettyReactiveWebServerFactory jettyReactiveWebServerFactory(
											JettyResourceFactory resourceFactory) {
			JettyReactiveWebServerFactory serverFactory = new JettyReactiveWebServerFactory();
			serverFactory.setResourceFactory(resourceFactory);
			return serverFactory;
		}

	}

	@Configuration
	@ConditionalOnMissingBean(ReactiveWebServerFactory.class)
	@ConditionalOnClass({ Undertow.class })
	static class EmbeddedUndertow {

		@Bean
		public UndertowReactiveWebServerFactory undertowReactiveWebServerFactory() {
			return new UndertowReactiveWebServerFactory();
		}

	}

}

总结

从上面的分析可见,方法createWebServer创建了Web服务器WebServer,包装在一个ServerManager中。所创建的WebServer是由容器中的一个ReactiveWebServerFactory bean来创建的,此ReactiveWebServerFactory beanSpring Boot自动配置类ReactiveWebServerFactoryAutoConfiguration定义,在本文章例子项目中,实际上是NettyReactiveWebServerFactory。并且该ReactiveWebServerFactory bean在创建时会被设置配置文件中所指定的参数:端口号参数,主机地址参数,SSL配置参数,压缩参数,HTTP2启用参数。

您可能感兴趣的与本文相关的镜像

Llama Factory

Llama Factory

模型微调
LLama-Factory

LLaMA Factory 是一个简单易用且高效的大型语言模型(Large Language Model)训练与微调平台。通过 LLaMA Factory,可以在无需编写任何代码的前提下,在本地完成上百种预训练模型的微调

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值