有2种主要的方式使用undertow,一种是直接在你的代码中嵌入undertow,另外一种是使用Wildfly应用服务器,我们主要关注于嵌入式的方式。
使用maven获取undertow,如下所示:
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-core</artifactId>
<version>${undertow.version}</version>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-servlet</artifactId>
<version>${undertow.version}</version>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-websockets-jsr</artifactId>
<version>${undertow.version}</version>
</dependency>
undertow提供3个独立的应用包,分别是:
- core,undertow的核心包,提供非阻塞IO机制和web socket,这个包可以单独使用
- servlet,servlet4.0支持,依赖core包
- Websockets JSR,websocket的Java API包
官方提供2种方式启动undertow,分别是:
- 使用undertow builder API
public class HelloWorldServer {
public static void main(final String[] args) {
Undertow server = Undertow.builder()
.addHttpListener(8080, "localhost")
.setHandler(new HttpHandler() {
@Override
public void handleRequest(final HttpServerExchange exchange) throws Exception {
exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain");
exchange.getResponseSender().send("Hello World");
}
}).build();
server.start();
}
}
上面示例启动一个服务器处理所有HTTP请求并返回"Hello World"字符串,这种方式的优点是简单,是最通用的一种方式。
- 手动装载服务 手动装载服务需要用到XNIO的API,undertow就是基于XNIO实现的高性能服务器,下面示例代码实现HTTP监听器:
Xnio xnio = Xnio.getInstance();
XnioWorker worker = xnio.createWorker(OptionMap.builder()
.set(Options.WORKER_IO_THREADS, ioThreads)
.set(Options.WORKER_TASK_CORE_THREADS, workerThreads)
.set(Options.WORKER_TASK_MAX_THREADS, workerThreads)
.set(Options.TCP_NODELAY, true)
.getMap());
OptionMap socketOptions = OptionMap.builder()
.set(Options.WORKER_IO_THREADS, ioThreads)
.set(Options.TCP_NODELAY, true)
.set(Options.REUSE_ADDRESSES, true)
.getMap();
Pool<ByteBuffer> buffers = new ByteBufferSlicePool(BufferAllocator.DIRECT_BYTE_BUFFER_ALLOCATOR,bufferSize, bufferSize * buffersPerRegion);
HttpOpenListener openListener = new HttpOpenListener(buffers, OptionMap.builder().set(UndertowOptions.BUFFER_PIPELINED_DATA, true).addAll(serverOptions).getMap(), bufferSize);
openListener.setRootHandler(rootHandler);
ChannelListener<AcceptingChannel<StreamConnection>> acceptListener = ChannelListeners.openListenerAdapter(openListener);
AcceptingChannel<? extends StreamConnection> server = worker.createStreamConnectionServer(new InetSocketAddress(Inet4Address.getByName(listener.host), listener.port), acceptListener, socketOptions);
server.resumeAccepts();
这种方式需要更多的代码,也有一定的复杂度,但更具灵活度:
- 所有步骤完全控制
- 对不同listerns使用不同buffer pools和workers
- 不同server实例可以使用同一个XnioWorker实例
- 不同server实例可以使用同一个buffer pools
- Listerns可以使用不同root handlers
对于大部分场景,这种级别的控制其实是不必要的,所以更好的方式是使用Buidler API。