Spring WebFlux - 定制NettyReactiveWebServerFactory

Spring的版本迭代很快,去年还是5.0,今年已经升级到5.1了。
别看只是小版本的升级,有些地方已经不兼容了。

比如,5.0时代,可以这样定制ConfigurableReactiveWebServerFactory:

    @Bean
    ConfigurableReactiveWebServerFactory webServerFactory() {
        NettyReactiveWebServerFactory factory = new NettyReactiveWebServerFactory();
        NettyServerCustomizer customizer = options ->
                options.eventLoopGroup(new NioEventLoopGroup(1)).option(CONNECT_TIMEOUT_MILLIS, 5000)
                        .afterNettyContextInit(context -> {
                            HttpServerRequest request = (HttpServerRequest) context;
                            if (URL_MQTT.equals(request.uri())) {
                                context.addHandlerFirst(IDLE_STATE_HANDLER,
                                        new IdleStateHandler(5, 0, 0));
                                context.addHandlerLast("idleEventHandler", new IdleTimeoutHandler());
                                context.addHandlerLast("ws2bytebufDecoder", new WebSocketFrameToByteBufDecoder());
                                context.addHandlerLast("bytebuf2wsEncoder", new ByteBufToWebSocketFrameEncoder());
                                context.addHandlerLast("decoder", new MqttDecoder());
                                context.addHandlerLast("encoder", MqttEncoder.INSTANCE);
                            } else if (request.uri().endsWith("/websocket")) {
                                context.addHandlerFirst(IDLE_STATE_HANDLER,
                                        new IdleStateHandler(5, 0, 0));
                                context.addHandlerLast("idleEventHandler", new IdleTimeoutHandler());

                            }
                        });
        factory.addServerCustomizers(customizer);
        return factory;
    }

到了5.1时代,很多底层类发生了变化。
新写的一个项目是这样定制的:

@Component
public class ServerCustomizationBean extends ReactiveWebServerFactoryCustomizer {

    public ServerCustomizationBean(ServerProperties serverProperties) {
        super(serverProperties);
    }

    @Override
    public void customize(ConfigurableReactiveWebServerFactory factory) {
        super.customize(factory);
        NettyReactiveWebServerFactory nettyFactory = (NettyReactiveWebServerFactory) factory;
        nettyFactory.setResourceFactory(null);
        nettyFactory.addServerCustomizers(server ->
                server.tcpConfiguration(tcpServer ->
                        tcpServer.runOn(LoopResources.create("server", 1, DEFAULT_IO_WORKER_COUNT, true))
                                .selectorOption(CONNECT_TIMEOUT_MILLIS, 10000)
                )
        );
    }
}

之所以要先nettyFactory.setResourceFactory(null),是因为本项目中,同时使用到了WebClient。在WebClient里,使用了自定义的ReactorResourceFactory。Spring在注入的时候,会自动注入到NettyReactiveWebServerFactory内。
查看NettyReactiveWebServerFactory类的源码:

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

可以得知,如果resourceFactory为null,就可以自定义LoopResources了。
自定义的LoopResources,selectCount为1,workerCount为:

	/**
	 * Default worker thread count, fallback to available processor
	 * (but with a minimum value of 4)
	 */
	int DEFAULT_IO_WORKER_COUNT = Integer.parseInt(System.getProperty(
			ReactorNetty.IO_WORKER_COUNT,
			"" + Math.max(Runtime.getRuntime()
			            .availableProcessors(), 4)));

默认option见TcpServerBind类:

	ServerBootstrap createServerBootstrap() {
		return new ServerBootstrap().option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
				.option(ChannelOption.SO_REUSEADDR, true)
				.option(ChannelOption.SO_BACKLOG, 1000)
				.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
				.childOption(ChannelOption.SO_RCVBUF, 1024 * 1024)
				.childOption(ChannelOption.SO_SNDBUF, 1024 * 1024)
				.childOption(ChannelOption.AUTO_READ, false)
				.childOption(ChannelOption.SO_KEEPALIVE, true)
				.childOption(ChannelOption.TCP_NODELAY, true)
				.childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, 30000)
				.localAddress(new InetSocketAddress(DEFAULT_PORT));
	}

debug一下:EventLoopGroup的线程数分别是1和8。
Spring WebFlux - 定制NettyReactiveWebServerFactory_第1张图片

你可能感兴趣的:(Spring5)