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。
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值