我有一个基于 Spring React 的微服务,它使用 Netty Server 版本 4.1.101.Final。 它工作得很好并处理我触发的所有 HTTP 请求。现在我想捕获连接 ID 以找出哪个连接正在使用以及哪个连接正在关闭。为此,我编写了一个自定义连接日志记录处理程序。以下是我的 ConnectionLoggingHandler :
public class ConnectionLoggingHandler extends ChannelInboundHandlerAdapter{
private static final AtomicInteger connectionIdCounter = new AtomicInteger(0);
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception{
int connectionId=connectionIdCounter.incrementAndGet();
System.out.println("Connection established : ID = " + connectionId);
ctx.channel().attr(AttributeKey.valueOf("connectionId")).set(connectionId);
super.channelActive(ctx);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception{
//retrieve connectionID
Integer connectionId = (Integer) ctx.channel().attr(AttributeKey.valueOf("connectionId")).get();
if(connectionId!=null){
System.out.println("Connection closed : ID = " + connectionId);
}
super.channelInactive(ctx);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception{
//retrieve connectionID
Integer connectionId = (Integer) ctx.channel().attr(AttributeKey.valueOf("connectionId")).get();
if(connectionId!=null){
System.out.println("Exception in Connection: ID = " + connectionId);
}
cause.printStackTrace();
ctx.close();
}
}
现在我想将此处理程序添加到我的 Netty 服务器中。我用两种方法尝试过。
自定义 Netty 服务器代码:
public class CustomNettyServer{
private int port =8080;
@PostConstruct
public void startServer() throws InterruptedException{
EventLoopGroup boss= new NioEventLoopGroup();
EventLoopGroup worker=new NioEventLoopGroup();
try{
ServerBootstrap bootstrap new ServerBootstrap();
bootstrap.group(boss,worker)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<Channel>(){
@Override
protected void initChannel(Channel ch) throws Exception{
ch.pipeline().addLast(new HttpServerCodec(),new HttpRequestDecoder(),new HttpContentDecompressor(),new HttpResponseEncoder(),new HttpContentCompressor(),new HttpObjectAggregator(512*1024),new ConnectionLoggingHandler());
}
});
Channel channel = bootstarp.bind(port).sync().channel();
channel.closeFuture().sync();
}
finally{
boss.shutdownGracefully();
worker.shutdownGracefully();
}
}
}
当我使用此服务器时,当我通过邮递员发出建立连接的请求时,我可以看到自定义处理程序中存在的日志。但我的 HTTP 请求没有得到处理。
它显示已丢弃入站消息。请检查您的管道配置。我不知道我在这里缺少什么。
然后我还尝试了另一种方法来定制我的netty服务器。下面是我的 CustomNettyServer 代码。
public class CustomNettyServer implements WebServerFactoryCustomizer<NettyReactiveWebServerFactory>{
@Override
public void customize(NettyReactiveWebServerFactory factory){
factory.addServerCustomizers(server->
server.tcpConfiguration(tcp->
tcp.doOnConnection(connection->
connection.addHandlerLast(new ConnectionLoggingHandler()))));
}
}
使用此方法,每当我点击请求并且请求成功处理时,由于我的 ConnectionLoggingHandler,我无法看到日志被打印。我可以看到 Handler 在发出请求时添加到管道中,并在处理请求时删除。但日志没有生成。我还将日志记录级别保持为 DEBUG。
我不知道我在这两种方式上做错了什么,我被困在这里。
所以我想知道如何获取正在打开、使用和关闭的 Connection-ID 的日志。
谢谢。
Reactor Netty(Spring WebFlux 使用的默认运行时)不使用 Netty 提供的 Bootstrap 类。
扩展 Reactor Netty 的正确方法是通过生命周期回调。 在您的示例中,您使用的是
doOnConnection
,但此时通道已经处于活动状态,并且您在 ConnectionLoggingHandler#channelActive
下的实现将永远不会被调用(检查 javadoc 中的 addHandlerLast)。
你最好使用回调doOnChannelInit
,如下
@Component
public class CustomNettyServer
implements WebServerFactoryCustomizer<NettyReactiveWebServerFactory> {
@Override
public void customize(NettyReactiveWebServerFactory factory) {
factory.addServerCustomizers(server ->
server.doOnChannelInit((obs, ch, addr) ->
ch.pipeline().addAfter(NettyPipeline.HttpCodec, "test", new ConnectionLoggingHandler())));
}
}