关于springcloud:Gateway集成Netty服务

40次阅读

共计 6827 个字符,预计需要花费 18 分钟才能阅读完成。

Gateway 和 Netty 都有盲区的感觉;

一、Netty 简介

Netty 是一个异步的,事件驱动的网络应用框架,用以疾速开发高牢靠、高性能的网络应用程序。

传输服务 :提供网络传输能力的治理;

协定反对 :反对常见的数据传输协定;

外围模块 :包含可扩大事件模型、通用的通信 API、零拷贝字节缓冲;

二、Netty 入门案例

1、服务端启动

配置 Netty 服务器端程序,疏导相干外围组件的加载;

public class NettyServer {public static void main(String[] args) {

        // EventLoop 组,处理事件和 IO
        EventLoopGroup parentGroup = new NioEventLoopGroup();
        EventLoopGroup childGroup = new NioEventLoopGroup();

        try {

            // 服务端启动疏导类
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(parentGroup, childGroup)
                    .channel(NioServerSocketChannel.class).childHandler(new ChannelInit());

            // 异步 IO 的后果
            ChannelFuture channelFuture = serverBootstrap.bind(8082).sync();
            channelFuture.channel().closeFuture().sync();} catch (Exception e){e.printStackTrace();
        } finally {parentGroup.shutdownGracefully();
            childGroup.shutdownGracefully();}
    }
}

2、通道初始化

ChannelInitializer 非凡的通道处理器,提供一种简略的办法,对注册到 EventLoop 的通道进行初始化;比方此处设置的编码解码器,自定义处理器;

public class ChannelInit extends ChannelInitializer<SocketChannel> {

    @Override
    protected void initChannel(SocketChannel socketChannel) {

        // 获取管道
        ChannelPipeline pipeline = socketChannel.pipeline();

        // Http 编码、解码器
        pipeline.addLast("DefHttpServerCodec",new HttpServerCodec());

        // 增加自定义的 handler
        pipeline.addLast("DefHttpHandler", new DefHandler());
    }
}

3、自定义处理器

解决对服务器端发动的拜访,通常包含申请解析,具体的逻辑执行,申请响应等过程;

public class DefHandler extends SimpleChannelInboundHandler<HttpObject> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, HttpObject message) throws Exception {if(message instanceof HttpRequest) {
            // 申请解析
            HttpRequest httpRequest = (HttpRequest) message;
            String uri = httpRequest.uri();
            String method = httpRequest.method().name();
            log.info("【HttpRequest-URI:"+uri+"】");
            log.info("【HttpRequest-method:"+method+"】");

            Iterator<Map.Entry<String,String>> iterator = httpRequest.headers().iteratorAsString();
            while (iterator.hasNext()){Map.Entry<String,String> entry = iterator.next();
                log.info("【Header-Key:"+entry.getKey()+";Header-Value:"+entry.getValue()+"】");
            }

            // 响应构建
            ByteBuf content = Unpooled.copiedBuffer("Netty 服务", CharsetUtil.UTF_8);
            FullHttpResponse response = new DefaultFullHttpResponse
                                        (HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content);
            response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain;charset=utf-8");
            response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());
            ctx.writeAndFlush(response);
        }
    }
}

4、测试申请

下面入门案例中,简略的配置了一个 Netty 服务器端,启动之后在浏览器中模仿拜访即可;

http://127.0.0.1:8082/?id=1&name=Spring

三、Gateway 集成

1、依赖层级

我的项目中 Gateway 网关依赖的版本为 2.2.5.RELEASE,发现 Netty 依赖的版本为 4.1.45.Final,是当下比拟支流的版本;

<!-- 1、我的项目工程依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
    <version>2.2.5.RELEASE</version>
</dependency>

<!-- 2、starter-gateway 依赖 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-webflux</artifactId>
  <version>2.3.2.RELEASE</version>
</dependency>

<!-- 3、starter-webflux 依赖 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-reactor-netty</artifactId>
  <version>2.3.2.RELEASE</version>
</dependency>

2、自动化配置

在 Gateway 网关的自动化配置配置类中,提供了 Netty 配置的治理;

@AutoConfigureBefore({HttpHandlerAutoConfiguration.class,WebFluxAutoConfiguration.class})
@ConditionalOnClass(DispatcherHandler.class)
public class GatewayAutoConfiguration {@Configuration(proxyBeanMethods = false)
    @ConditionalOnClass(HttpClient.class)
    protected static class NettyConfiguration {

        @Bean
        @ConditionalOnProperty(name = "spring.cloud.gateway.httpserver.wiretap")
        public NettyWebServerFactoryCustomizer nettyServerWiretapCustomizer(Environment environment, ServerProperties serverProperties) {return new NettyWebServerFactoryCustomizer(environment, serverProperties) {
                @Override
                public void customize(NettyReactiveWebServerFactory factory) {factory.addServerCustomizers(httpServer -> httpServer.wiretap(true));
                    super.customize(factory);
                }
            };
        }
    }
}

四、配置加载

1、根底配置

在工程的配置文件中,简略做一些基础性的设置;

server:
  port: 8081                  # 端口号
  netty:                      # Netty 组件
    connection-timeout: 3000  # 连贯超时 

2、属性配置类

在 ServerProperties 类中,并没有提供很多显式的 Netty 配置参数,更多信息须要参考工厂类;

@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {
    private Integer port;
    public static class Netty {private Duration connectionTimeout;}
}

3、配置加载剖析

  • 基于配置的属性,定制化治理 Netty 服务的信息;
public class NettyWebServerFactoryCustomizer
        implements WebServerFactoryCustomizer<NettyReactiveWebServerFactory>{
    private final Environment environment;
    private final ServerProperties serverProperties;
    @Override
    public void customize(NettyReactiveWebServerFactory factory) {PropertyMapper propertyMapper = PropertyMapper.get().alwaysApplyingWhenNonNull();
        ServerProperties.Netty nettyProperties = this.serverProperties.getNetty();
        propertyMapper.from(nettyProperties::getConnectionTimeout).whenNonNull()
                .to((connectionTimeout) -> customizeConnectionTimeout(factory, connectionTimeout));
    }
}
  • NettyReactiveWeb 服务工厂,基于上述入门案例,创立 WebServer 时,局部参数信息出自 LoopResources 接口;
public class NettyReactiveWebServerFactory extends AbstractReactiveWebServerFactory {

    private ReactorResourceFactory resourceFactory;

    @Override
    public WebServer getWebServer(HttpHandler httpHandler) {HttpServer httpServer = createHttpServer();
        ReactorHttpHandlerAdapter handlerAdapter = new ReactorHttpHandlerAdapter(httpHandler);
        NettyWebServer webServer = new NettyWebServer(httpServer, handlerAdapter, this.lifecycleTimeout);
        webServer.setRouteProviders(this.routeProviders);
        return webServer;
    }
    
    private HttpServer createHttpServer() {HttpServer server = HttpServer.create();
        if (this.resourceFactory != null) {LoopResources resources = this.resourceFactory.getLoopResources();
            server = server.tcpConfiguration((tcpServer) -> tcpServer.runOn(resources).addressSupplier(this::getListenAddress));
        }
        return applyCustomizers(server);
    }
    
}

五、周期治理办法

1、管制类

Gateway 我的项目中,Netty 服务外围管制类,通过 NettyReactiveWebServerFactory 工厂类创立,对 Netty 生命周期的治理提供了一层包装;

public class NettyWebServer implements WebServer {

    private final HttpServer httpServer;
    private final ReactorHttpHandlerAdapter handlerAdapter;

    /**
     * 启动办法
     */
    @Override
    public void start() throws WebServerException {if (this.disposableServer == null) {this.disposableServer = startHttpServer();
            // 控制台日志
            logger.info("Netty started on port(s):" + getPort());
            startDaemonAwaitThread(this.disposableServer);
        }
    }
    private DisposableServer startHttpServer() {
        HttpServer server = this.httpServer;
        if (this.routeProviders.isEmpty()) {server = server.handle(this.handlerAdapter);
        }
        return server.bindNow();}

    /**
     * 进行办法
     */
    @Override
    public void stop() throws WebServerException {if (this.disposableServer != null) {
            // 开释资源
            if (this.lifecycleTimeout != null) {this.disposableServer.disposeNow(this.lifecycleTimeout);
            }
            else {this.disposableServer.disposeNow();
            }
            // 对象销毁
            this.disposableServer = null;
        }
    }
}

2、治理类

Netty 组件中形象治理类,以平安的形式构建 Http 服务;

public abstract class HttpServer {public static HttpServer create() {return HttpServerBind.INSTANCE;}

    public final DisposableServer bindNow() {return bindNow(Duration.ofSeconds(45));
    }

    public final HttpServer handle(BiFunction<? super HttpServerRequest, ? super
            HttpServerResponse, ? extends Publisher<Void>> handler) {return new HttpServerHandle(this, handler);
    }
}

六、参考源码

 编程文档:https://gitee.com/cicadasmile/butte-java-note

利用仓库:https://gitee.com/cicadasmile/butte-flyer-parent

正文完
 0