Undertown。异步响应另一个线程

时间:2017-11-24 00:21:36

标签: java multithreading http asynchronous undertow

我尝试了解如何使用Undertow构建一个真正的异步http服务器。如果我有另一个正在处理请求的线程,如何异步发送响应? 我写了这样的代码:

    Undertow server = Undertow.builder()
            .addHttpListener(8080, "localhost")
            .setHandler(exchange -> {
                CompletableFuture.runAsync(() -> {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }).thenAccept(string -> {
                    exchange.getResponseHeaders()
                            .put(Headers.CONTENT_TYPE, "text/plain");
                    exchange.getResponseSender().send("Hello World");
                    exchange.endExchange();
                }).exceptionally(throwable -> {
                    System.out.println(throwable.toString());
                    return null;
                });
            }).build();
    server.start();

但此服务器响应200没有数据且在日志中

  

java.lang.IllegalStateException:UT000127:已发送响应

当我像这样使用io.undertow.server.HttpServerExchange#dispatch(java.lang.Runnable)方法时:

    Undertow server = Undertow.builder()
            .addHttpListener(8080, "localhost")
            .setHandler(exchange -> {

                exchange.dispatch(() -> {

                    CompletableFuture.runAsync(() -> {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }).thenAccept(string -> {
                        exchange.getResponseHeaders()
                                .put(Headers.CONTENT_TYPE,"text/plain");
                        exchange.getResponseSender().send("Hello World");
                        exchange.endExchange();
                    }).exceptionally(throwable -> {
                        System.out.println(throwable.toString());
                        return null;
                    });

                });
            }).build();
    server.start();

当然是回应" Hello World"正如所料,但服务器为每个请求创建新线程!

(10次并行请求后的jvisualvm) jvisualvm after 10 parallel requests

1 个答案:

答案 0 :(得分:0)

承诺不支持这种方式,

我创建了一个新项目来解决它:

https://github.com/hank-whu/undertow-async

package io.undertow.async.pingpong;

import java.io.IOException;
import java.util.concurrent.CompletableFuture;

import io.undertow.async.handler.AsyncHttpHandler;
import io.undertow.async.io.PooledByteBufferInputStream;
import io.undertow.async.io.PooledByteBufferOutputStream;
import io.undertow.connector.ByteBufferPool;
import io.undertow.server.HttpServerExchange;
import io.undertow.util.StatusCodes;

public class PingPongAsyncHttpHandler extends AsyncHttpHandler {

    @Override
    protected void handleAsyncRequest(HttpServerExchange exchange, PooledByteBufferInputStream content)
            throws Exception {

        CompletableFuture//
                .completedFuture(content)// init
                .thenApplyAsync(this::readBytesAndClose)// read
                .thenApplyAsync(bytes -> {// write
                    ByteBufferPool byteBufferPool = exchange.getConnection().getByteBufferPool();
                    PooledByteBufferOutputStream output = new PooledByteBufferOutputStream(byteBufferPool);
                    write(output, bytes);
                    return output;
                })//
                .thenAcceptAsync(output -> send(exchange, StatusCodes.OK, output));
    }

    private byte[] readBytesAndClose(PooledByteBufferInputStream content) {
        try {
            byte[] bytes = new byte[content.available()];
            content.read(bytes);
            return bytes;
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {// must close it
                content.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void write(PooledByteBufferOutputStream output, byte[] bytes) {
        try {
            output.write("asycn response: ");
            output.write(bytes);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}