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