我注意到没有为每个http请求创建处理程序的新实例。我在实例级别定义的变量很少。这些值是根据要求设置的。通过仔细检查,我发现这些值不是刚设置的,而是具有第一个请求中的值。
这是我的处理程序代码
@Component
@ChannelHandler.Sharable
public class CustomHandler extends ChannelDuplexHandler {
private final StringBuilder buf = new StringBuilder();
private final String foo;
private final String val;
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
//parse the request and set the variables
if (foo!=null) {
foo = request.getUri()
}
if (val!=null) {
val = getQueryParamsOf("key");
}
buf.append(val);
}
}
缓冲区未清除。对于每个新请求,我仍然看到旧缓冲区。
也就是说,如果我发出请求/foobar?key=netty
我在第一个电话中看到 buf = netty 。
随后的调用 buf = nettynetty 和 buf = nettynettynetty 等。
此外,在第一个请求之后,foo
和val
变量永远不会为空。
我的理解是,因为将为每个请求创建新的处理程序。但是由于我使用过@ChannelHander.Sharable
,可能会重复使用相同的处理程序
所以我注释了@ChannelHander.Sharable
,第一个请求通过了。在下一个请求中,出现以下错误。
io.netty.channel.ChannelPipelineException: my.example.handlers.CustomHandler is not a @Sharable handler, so can't be added or removed multiple times.
at io.netty.channel.DefaultChannelPipeline.checkMultiplicity(DefaultChannelPipeline.java:625)
at io.netty.channel.DefaultChannelPipeline.addLast(DefaultChannelPipeline.java:208)
at io.netty.channel.DefaultChannelPipeline.addLast(DefaultChannelPipeline.java:409)
at io.netty.channel.DefaultChannelPipeline.addLast(DefaultChannelPipeline.java:396)
at my.example.CustomInitializer.initChannel(CustomInitializer.java:35)
at my.example.CustomInitializer.initChannel(CustomInitializer.java:16)
at io.netty.channel.ChannelInitializer.initChannel(ChannelInitializer.java:113)
at io.netty.channel.ChannelInitializer.handlerAdded(ChannelInitializer.java:105)
at io.netty.channel.DefaultChannelPipeline.callHandlerAdded0(DefaultChannelPipeline.java:637)
这是我的初始化代码
CustomIniatializer
public class CustomIniatializer extends ChannelInitializer<SocketChannel> {
@Autowired
private ChannelDuplexHandler customHandler;
@Override
public void initChannel(SocketChannel ch) {
ChannelPipeline p = ch.pipeline();
p.addLast(new LoggingHandler(LogLevel.INFO));
p.addLast(new HttpServerCodec());
p.addLast(new HttpObjectAggregator(8*1024, true));
p.addLast(customHandler);
}
}
答案 0 :(得分:2)
使用ChannelInitializer
时要记住的一件事是,对于每个打开的新连接都调用方法initChannel
。
任何需要唯一状态的东西都应该在此方法内构造。
查看您的代码,我发现您正在正确创建LoggingHandler
,HttpServerCodec
和HttpObjectAggregator
的新实例,但是您引用的是{{ 1}}类。
虽然您可以只使用customHandler
方法内的new CustomHandler ()
来解决问题,但实际上您通过使用springs自动接线系统显示了不同的意图。
我们可以使用其他2种解决方案:
代替直接自动装配initChannel
的实例,您需要连接一个产生此类实例的工厂:
ChannelDuplexHandler
您可以使用的另一种解决方案是存储在当前通道内部的变量,这是一种更先进的技术,可在某些情况下使用:
public interface ChannelDuplexHandlerFactory {
public ChannelDuplexHandler getChannelDuplexHandler();
}
@Component
public class ChannelDuplexHandlerFactoryImplementation implements ChannelDuplexHandlerFactory {
public ChannelDuplexHandler getChannelDuplexHandler() {
return new CustomHandler();
}
}
public class CustomIniatializer extends ChannelInitializer<SocketChannel> {
@Autowired
private ChannelDuplexHandler customHandler;
@Override
public void initChannel(SocketChannel ch) {
ChannelPipeline p = ch.pipeline();
p.addLast(new LoggingHandler(LogLevel.INFO));
p.addLast(new HttpServerCodec());
p.addLast(new HttpObjectAggregator(8*1024, true));
p.addLast(customHandler.getChannelDuplexHandler());
}
}
答案 1 :(得分:0)
即使使用新的Handler()实现,我也遇到相同的问题
public class HttpServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
public void initChannel(SocketChannel ch) throws Exception {
.....
p.addLast("httprequest", new HttpServerHandler(config));
}
}
HttpServerHander
private String uuid;
public HttpServerHandler(final StaticConfig staticConfig) {
this.uuid = UUID.randomUUID().toString();
}
此uuid并非每次通话都唯一。