Reactor Netty 启动 Http Server 过程的源码解读

1. Netty Reactor创建 Http Server

1.1 核心类图

通过HttpServer -> FtpServer -> ServerBootStrap的配置顺序实现ServerBootStrap的最终配置。配置是通过函数式编程来实现,代码读起来有些费劲,所以特意整理了NettyHttpServer配置相关的核心类图,帮助理解。

主流程是HttpServer -> HttpServerBind -> TcpServer -> TcpServerBind -> ServerBootstrap。
HttpServerOperator和TcpServerOperator是对HttpServerBind和TCPServerBind的一系列操作,可以实现HttpServerOperator和TcpServerOperator的多层嵌套。
在这里插入图片描述

1.2 对象关系图

Netty Http Server从配置到启动大致经历了如下阶段:

  1. HttpServer配置阶段:
    1.1 创建HttpServerBind实例,并通过HttpServerTcpConfig对实例绑定的TcpServerBind实例进行配置。
    1.2 创建HttpServerHandle实例,绑定ReactorHttpHandlerAdaptor
  2. TcpServer配置阶段:
    2.1 由HttpServerHandle实例逐级溯源到HttpServerBind获取TcpServerBind实例,然后执行各HttpServerTcpConfig实例的tcpServerMapper函数对TcpServerBind进行配置。
    2.2 HttpServerHandle自身也是Function<ServerBootstrap, ServerBootstrap>的实现类,启用HttpServerHandle实例自身对TcpServerBind进行配置。
    2.3 HttpServerBind自身也是Function<ServerBootstrap, ServerBootstrap>的实现类,启用HttpServerBind实例自身对TcpServerBind进行配置。
  3. ServerBootstrap配置阶段
    3.1 TcpServerBind创建ServerBootstrap实例,然后由操作对象TcpServerRunOn以及各TcpServerBootstrap对实例进行配置
    3.2 逐级调用TcpServerBootstrap、TcpServerRunOn的bind(ServerBootstrap b)方法进行绑定操作,最终调用TcpServerBind进行最终绑定操作。
    在这里插入图片描述

1.2.1 Http Server配置阶段

函数式编程的代码不好理解,比较关键的一点是函数作为参数传递时并未真正开始执行,而是在调用函数方法时才真正被执行。
在创建HttpServer时,会执行下述方法。

org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory#createHttpServer

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));
	}
	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);
}

其中,HttpServer.create() 方法会创建 HttpServerBind 的实例,它包含一个 TcpServer 的成员,该成员初始化为 TcpServerBind 的实例。
TcpServerBind 包含 ServerBootstrap 的成员,该成员也会进行初始化并进行相关设置。

TcpServerBind() {
	// 创建ServerBootstrap对象
	this.serverBootstrap = createServerBootstrap();
	// 设置ops_factory为reactor.netty.channel.ChannelOperations,该option是reactor自定义option
	BootstrapHandlers.channelOperationFactory(this.serverBootstrap, TcpUtils.TCP_OPS);
}

ServerBootstrap createServerBootstrap() {
	return new ServerBootstrap()
		.option(ChannelOption.SO_REUSEADDR, true)
		.childOption(ChannelOption.AUTO_READ, false)
		.childOption(ChannelOption.TCP_NODELAY, true)
		.localAddress(new InetSocketAddress(DEFAULT_PORT));
}

可以通过调用下述方法对 TcpServer 进行配置,该方法传递的是一个函数参数,这时函数本身并没有执行,而是存储到 HttpServerTcpConfig 对象 tcpServerMapper 属性。

reactor.netty.http.server.HttpServer#tcpConfiguration(java.util.function.Function<? super reactor.netty.tcp.TcpServer,? extends reactor.netty.tcp.TcpServer>)

在执行 createHttpServer() 的过程中对 TcpServer 进行了如下几个配置。

tcpConfiguration((tcpServer) -> tcpServer.runOn(resources).addressSupplier(this::getListenAddress))

tcpConfiguration(tcpServer -> tcpServer.bootstrap(b -> HttpServerConfiguration.protocols(b, supportedProtocols)))

tcpConfiguration(FORWARD_ATTR_DISABLE)

tcpConfiguration(requestDecoderOptions.apply(new HttpRequestDecoderSpec()).build())

执行完 createHttpServer() 方法后 httpServer 对象的结构如下图所示,可以看到 httpServer 对象其实是 tcpServerMapperSource 的多层嵌套,现阶段 tcpServerMapper 只停留在配置层面,并未真正执行。
在这里插入图片描述
关于 HttpServerHandle 的配置从代码层面讲并不是在这个阶段完成的,而是在Netty Http Server的启动阶段。
org.springframework.boot.web.embedded.netty.NettyWebServer#startHttpServer

private DisposableServer startHttpServer() {
	if (this.lifecycleTimeout != null) {
		return this.httpServer.handle(this.handlerAdapter)
				.bindNow(this.lifecycleTimeout);
	}
	return this.httpServer.handle(this.handlerAdapter).bindNow();
}

至此,HttpServer的配置全部完成。

1.2.2 TcpServer配置阶段

Netty Http Server启动时会调用 reactor.netty.http.server.HttpServer#bind() 方法,但是执行 bind() 之前,先要通过 tcpConfiguration() 进行 TcpServer 的配置。

public final Mono<? extends DisposableServer> bind() {
	return bind(tcpConfiguration());
}

tcpConfiguration() 通过层层调用,最终会产生一个类型为 TcpServerBootstrap 的对象。

另外还有比较隐蔽的两处:
reactor.netty.http.server.HttpServerHandle#tcpConfiguration

@Override
protected TcpServer tcpConfiguration() {
	return source.tcpConfiguration().bootstrap(this);
}

reactor.netty.http.server.HttpServerBind#bind

@Override
@SuppressWarnings("unchecked")
public Mono<? extends DisposableServer> bind(TcpServer delegate) {
	return delegate.bootstrap(this)
	               .bind()
	               .map(CLEANUP_GLOBAL_RESOURCE);
}

通过层层处理,最终的TcpServer配置信息如下图示。
在这里插入图片描述

1.2.3 ServerBootstrap配置阶段

ServerBootstrap 的配置主要是通过下述方法实现。其中 configure() 方法主要负责对 ServerBootstrap 进行配置,bind(b) 则负责最终的绑定操作。
reactor.netty.tcp.TcpServer#bind()

public final Mono<? extends DisposableServer> bind() {
	ServerBootstrap b;
	try{
		b = configure();
	}
	catch (Throwable t){
		Exceptions.throwIfJvmFatal(t);
		return Mono.error(t);
	}
	return bind(b);
}

配置完成后 disposableServer 对象的值参考下图。
在这里插入图片描述

其中几个比较核心的方法罗列如下:
reactor.netty.http.server.HttpServerBind#apply : 配置ServerBootstrap
reactor.netty.tcp.TcpServerBind#bind : 最终绑定操作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值