Jersey 如何使用Netty';s通道池映射作为Jax RS客户端的ConnectorProvider

Jersey 如何使用Netty';s通道池映射作为Jax RS客户端的ConnectorProvider,jersey,jax-rs,netty,Jersey,Jax Rs,Netty,我已经浪费了几个小时试图解决一个使用netty的通道池映射和jax-rs客户端的问题 我用泽西岛自己的netty connector作为灵感,但用netty的频道池地图交换了netty的频道 我的问题是,我的自定义SimpleChannelInboundHandler中有我需要的引用。然而,根据netty创建通道池映射的方法的设计,我无法通过我的定制ChannelPoolHandler传递引用,因为一旦池映射创建了一个池,通道池处理程序的构造函数就再也不会运行了 这是它获取池并签出通道以发出H

我已经浪费了几个小时试图解决一个使用netty的通道池映射和jax-rs客户端的问题

我用泽西岛自己的netty connector作为灵感,但用netty的频道池地图交换了netty的频道

我的问题是,我的自定义SimpleChannelInboundHandler中有我需要的引用。然而,根据netty创建通道池映射的方法的设计,我无法通过我的定制ChannelPoolHandler传递引用,因为一旦池映射创建了一个池,通道池处理程序的构造函数就再也不会运行了

这是它获取池并签出通道以发出HTTP请求的方法

    @Override
public Future<?> apply(ClientRequest request, AsyncConnectorCallback callback) {
    final CompletableFuture<Object> completableFuture = new CompletableFuture<>();

    try{
        HttpRequest httpRequest = buildHttpRequest(request);

        // guard against prematurely closed channel
        final GenericFutureListener<io.netty.util.concurrent.Future<? super Void>> closeListener =
                future -> {
                    if (!completableFuture.isDone()) {
                        completableFuture.completeExceptionally(new IOException("Channel closed."));
                    }
                };

        try {
            ClientRequestDTO clientRequestDTO = new ClientRequestDTO(NettyChannelPoolConnector.this, request, completableFuture, callback);
            dtoMap.putIfAbsent(request.getUri(), clientRequestDTO);

            // Retrieves a channel pool for the given host
            FixedChannelPool pool = this.poolMap.get(clientRequestDTO);

            // Acquire a new channel from the pool
            io.netty.util.concurrent.Future<Channel> f = pool.acquire();

            f.addListener((FutureListener<Channel>) futureWrite -> {
                //Succeeded with acquiring a channel
                if (futureWrite.isSuccess()) {
                    Channel channel = futureWrite.getNow();

                    channel.closeFuture().addListener(closeListener);

                    try {
                        if(request.hasEntity()) {
                            channel.writeAndFlush(httpRequest);

                            final JerseyChunkedInput jerseyChunkedInput = new JerseyChunkedInput(channel);
                            request.setStreamProvider(contentLength -> jerseyChunkedInput);

                            if(HttpUtil.isTransferEncodingChunked(httpRequest)) {
                                channel.write(jerseyChunkedInput);
                            } else {
                                channel.write(jerseyChunkedInput);
                            }

                            executorService.execute(() -> {
                                channel.closeFuture().removeListener(closeListener);

                                try {
                                    request.writeEntity();
                                } catch (IOException ex) {
                                    callback.failure(ex);
                                    completableFuture.completeExceptionally(ex);
                                }
                            });
                            channel.flush();
                        } else {
                            channel.closeFuture().removeListener(closeListener);
                            channel.writeAndFlush(httpRequest);
                        }

                    } catch (Exception ex) {
                        System.err.println("Failed to sync and flush http request" + ex.getLocalizedMessage());
                    }
                    pool.release(channel);
                }
            });
        } catch (NullPointerException ex) {
            System.err.println("Failed to acquire socket from pool " + ex.getLocalizedMessage());
        }

    } catch (Exception ex) {
        completableFuture.completeExceptionally(ex);
        return completableFuture;
    }
    return completableFuture;
}
}

这是我的SimpleInboundHandler

public class JerseyNettyClientHandler extends SimpleChannelInboundHandler<HttpObject> {

private final NettyChannelPoolConnector nettyChannelPoolConnector;
private final LinkedBlockingDeque<InputStream> isList = new LinkedBlockingDeque<>();

private final AsyncConnectorCallback asyncConnectorCallback;
private final ClientRequest jerseyRequest;
private final CompletableFuture future;

public JerseyNettyClientHandler(ClientRequestDto clientRequestDTO) {
    this.nettyChannelPoolConnector = clientRequestDTO.getNettyChannelPoolConnector();

    ClientRequestDTO cdto = clientRequestDTO.getNettyChannelPoolConnector().getDtoMap().get(clientRequestDTO.getClientRequest());

    this.asyncConnectorCallback = cdto.getCallback();
    this.jerseyRequest = cdto.getClientRequest();
    this.future = cdto.getFuture();
}

@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
    if(msg instanceof HttpResponse) {

        final HttpResponse httpResponse = (HttpResponse) msg;

        final ClientResponse response = new ClientResponse(new Response.StatusType() {
            @Override
            public int getStatusCode() {
                return httpResponse.status().code();
            }

            @Override
            public Response.Status.Family getFamily() {
                return Response.Status.Family.familyOf(httpResponse.status().code());
            }

            @Override
            public String getReasonPhrase() {
                return httpResponse.status().reasonPhrase();
            }
        }, jerseyRequest);

        for (Map.Entry<String, String> entry : httpResponse.headers().entries()) {
            response.getHeaders().add(entry.getKey(), entry.getValue());
        }

        if((httpResponse.headers().contains(HttpHeaderNames.CONTENT_LENGTH) && HttpUtil.getContentLength(httpResponse) > 0) || HttpUtil.isTransferEncodingChunked(httpResponse)) {
            ctx.channel().closeFuture().addListener(future -> isList.add(NettyInputStream.END_OF_INPUT_ERROR));
            response.setEntityStream(new NettyInputStream(isList));
        } else {
            response.setEntityStream(new InputStream() {
                @Override
                public int read() {
                    return -1;
                }
            });
        }

        if(asyncConnectorCallback != null) {
            nettyChannelPoolConnector.executorService.execute(() -> {
                asyncConnectorCallback.response(response);
                future.complete(response);
            });
        }
    }

    if(msg instanceof HttpContent) {
        HttpContent content = (HttpContent) msg;

        ByteBuf byteContent = content.content();

        if(byteContent.isReadable()) {
            byte[] bytes = new byte[byteContent.readableBytes()];
            byteContent.getBytes(byteContent.readerIndex(), bytes);
            isList.add(new ByteArrayInputStream(bytes));
        }
    }

    if(msg instanceof LastHttpContent) {
        isList.add(NettyInputStream.END_OF_INPUT);
    }
}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    if(asyncConnectorCallback != null) {
        nettyChannelPoolConnector.executorService.execute(() -> asyncConnectorCallback.failure(cause));
    }
    future.completeExceptionally(cause);
    isList.add(NettyInputStream.END_OF_INPUT_ERROR);
}
公共类JerseyNetCyclientHandler扩展了SimpleChannelInboundHandler{
专用最终NettyChannel PoolConnector NettyChannel PoolConnector;
private final LinkedBlockingDeque isList=new LinkedBlockingDeque();
专用最终AsyncConnectorCallback AsyncConnectorCallback;
私人最终客户请求;
私人最终可完成的未来;
public Jersey NettyClientHandler(ClientRequestDto ClientRequestDto){
this.nettyChannelPoolConnector=clientRequestDTO.getNettyChannelPoolConnector();
ClientRequestDTO cdto=ClientRequestDTO.getNettyChannelPoolConnector().getDtoMap().get(ClientRequestDTO.getClientRequest());
this.asyncConnectorCallback=cdto.getCallback();
this.jerseyRequest=cdto.getClientRequest();
this.future=cdto.getFuture();
}
@凌驾
受保护的无效channelRead0(ChannelHandlerContext ctx,HttpObject msg)引发异常{
if(HttpResponse的消息实例){
最终HttpResponse HttpResponse=(HttpResponse)消息;
final ClientResponse response=new ClientResponse(new response.StatusType()){
@凌驾
public int getStatusCode(){
返回httpResponse.status().code();
}
@凌驾
public Response.Status.Family getFamily(){
返回Response.Status.Family.familyOf(httpResponse.Status().code());
}
@凌驾
公共字符串getReasonPhrase(){
返回httpResponse.status().reasonPhrase();
}
},JerseyeRequest);
对于(Map.Entry:httpResponse.headers().entries()){
response.getHeaders().add(entry.getKey(),entry.getValue());
}
if((httpResponse.headers().contains(HttpHeaderNames.CONTENT_LENGTH)&&HttpUtil.getContentLength(httpResponse)>0)| | HttpUtil.isTransferEncodingChunked(httpResponse)){
ctx.channel().closeFuture().addListener(future->isList.add(NettyInputStream.END\u OF_INPUT\u ERROR));
response.setEntityStream(新NettyInputStream(isList));
}否则{
response.setEntityStream(新的InputStream(){
@凌驾
公共int read(){
返回-1;
}
});
}
if(asyncConnectorCallback!=null){
NettyChannel PoolConnector.executorService.execute(()->{
asyncConnectorCallback.response(响应);
未来。完成(回应);
});
}
}
if(HttpContent的消息实例){
HttpContent=(HttpContent)msg;
ByteBuf byteContent=content.content();
if(byteContent.isReadable()){
字节[]字节=新字节[byteContent.readableBytes()];
byteContent.getBytes(byteContent.readerIndex(),字节);
add(新的ByteArrayInputStream(字节));
}
}
if(msg instanceof LastHttpContent){
添加(NettyInputStream.END\u的输入);
}
}
@凌驾
public void exceptionCaught(ChannelHandlerContext ctx,可丢弃原因)引发异常{
if(asyncConnectorCallback!=null){
NettyChannel PoolConnector.executorService.execute(()->asyncConnectorCallback.failure(原因));
}
未来。完全例外(原因);
isList.add(NettyInputStream.END\u输入错误);
}

需要传递给SimpleChannelInboundHandler的引用是打包到ClientRequestDTO中的引用,如第一个代码块所示。

我不确定,因为它不是经过测试的代码。但可以通过以下代码实现

        SimpleChannelPool sPool = poolMap.get(Req.getAddress());
        Future<Channel> f = sPool.acquire();
        f.get().pipeline().addLast("inbound", new NettyClientInBoundHandler(Req, jbContext, ReportData));
        f.addListener(new NettyClientFutureListener(this.Req, sPool));
SimpleChannelPool sPool=poolMap.get(Req.getAddress());
Future f=sPool.acquire();
f、 get().pipeline().addLast(“入站”,新的NettyClientInBoundHandler(Req、jbContext、ReportData));
f、 addListener(新NetCyclientFutureListener(this.Req,sPool));
其中Req、jbContext、ReportData可以是InboundHandler()的输入数据

        SimpleChannelPool sPool = poolMap.get(Req.getAddress());
        Future<Channel> f = sPool.acquire();
        f.get().pipeline().addLast("inbound", new NettyClientInBoundHandler(Req, jbContext, ReportData));
        f.addListener(new NettyClientFutureListener(this.Req, sPool));