未为netty中的每个请求创建新的处理程序

时间:2019-04-09 19:36:56

标签: netty

我注意到没有为每个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 等。 此外,在第一个请求之后,fooval变量永远不会为空。

我的理解是,因为将为每个请求创建新的处理程序。但是由于我使用过@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);
    }
}

2 个答案:

答案 0 :(得分:2)

使用ChannelInitializer时要记住的一件事是,对于每个打开的新连接都调用方法initChannel

任何需要唯一状态的东西都应该在此方法内构造。

查看您的代码,我发现您正在正确创建LoggingHandlerHttpServerCodecHttpObjectAggregator的新实例,但是您引用的是{{ 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并非每次通话都唯一。