Introduction to JBoss Undertow – JBoss Undertow简介

最后修改: 2017年 8月 21日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Undertow is an extremely lightweight and high-performance web server from JBoss. It supports both blocking and non-blocking APIs with NIO.

Undertow是一个来自JBoss的极其轻量级和高性能的Web服务器。它通过NIO支持阻塞和非阻塞API。

Since it’s written is Java, it can be used in any JVM-based applications in embedded mode, even JBoss’s WilfFly server internally uses Undertow to improve the server’s performance.

由于它是用Java编写的,它可以在任何基于JVM的应用程序中以嵌入式模式使用,甚至JBoss的WilfFly服务器在内部使用Undertow来提高服务器的性能。

In this tutorial, we’ll show the features of Undertow and how to use it.

在本教程中,我们将展示Undertow的功能和如何使用它。

2. Why Undertow?

2.为什么是暗渡陈仓?

  • Lightweight: Undertow is extremely lightweight at under 1MB. In embedded mode, it uses only 4MB of heap space at runtime
  • Servlet 3.1: It fully supports Servlet 3.1
  • Web Socket: It supports Web Socket functionality (including JSR-356)
  • Persistent Connection: By default, Undertow includes HTTP persistent connections by adding keep-alive response header. It helps clients that support persistent connections to optimize performance by reusing connection details

3. Using Undertow

3.使用暗渡陈仓

Let’s start to use Undertow by creating a simple web server.

让我们通过创建一个简单的网络服务器来开始使用Undertow

3.1. Maven Dependency

3.1.Maven的依赖性

To use Undertow, we need to add the following dependency to our pom.xml:

为了使用Undertow,我们需要在pom.xml中添加以下依赖。

<dependency>
    <groupId>io.undertow</groupId>
    <artifactId>undertow-servlet</artifactId>
    <version>1.4.18.Final</version>
</dependency>

To build a runnable jar, we also need to add maven-shade-plugin. That’s why we also need to add below configuration as well:

为了构建一个可运行的jar,我们还需要添加maven-shad-plugin。这就是为什么我们还需要添加以下配置。

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
        </execution>
    </executions>
</plugin>

The latest version of Undertow is available in Central Maven Repository.

Undertow的最新版本在Central Maven Repository中提供。

3.2. Simple Server

3.2.简单的服务器

With the below code snippet, we can create a simple web server using Undertow’s Builder API:

通过下面的代码片段,我们可以使用Undertow的Builder API创建一个简单的Web服务器。

public class SimpleServer {
    public static void main(String[] args) {
        Undertow server = Undertow.builder().addHttpListener(8080, 
          "localhost").setHandler(exchange -> {
            exchange.getResponseHeaders()
            .put(Headers.CONTENT_TYPE, "text/plain");
          exchange.getResponseSender().send("Hello Baeldung");
        }).build();
        server.start();
    }
}

Here, we’ve used the Builder API to bind 8080 port to this server. Also, note that we have used a lambda expression to use the handler.

在这里,我们使用了Builder API,将8080端口与该服务器绑定。另外,请注意,我们使用了一个lambda表达式来使用处理程序。

We can also use below code snippet to do the same thing without using lambda expressions:

我们也可以使用下面的代码片断来做同样的事情,而不使用lambda表达式。

Undertow server = Undertow.builder().addHttpListener(8080, "localhost")
  .setHandler(new HttpHandler() {
      @Override
      public void handleRequest(HttpServerExchange exchange) 
        throws Exception {
          exchange.getResponseHeaders().put(
            Headers.CONTENT_TYPE, "text/plain");
          exchange.getResponseSender().send("Hello Baeldung");
      }
  }).build();

The important thing to note here is the usage of the HttpHandler API. It’s the most important plugin to customize an Undertow application based on our needs.

这里需要注意的是HttpHandler API的使用。这是最重要的插件,可以根据我们的需要定制一个Undertow应用程序。

In this case, we have added a customized handler that would add the Content-Type: text/plain response header with each request.

在这种情况下,我们添加了一个定制的处理程序,将在每个请求中添加Content-Type: text/plain响应头。

Similar way, if we want to return some default text with each response, we can use below code snippet:

类似地,如果我们想在每个响应中返回一些默认文本,我们可以使用下面的代码片段。

exchange.getResponseSender()
  .send("Hello Baeldung");

3.3. Secure Access

3.3.安全访问

In most cases, we don’t allow all users to access our server. Usually, users with valid credentials can get access.We can implement the same mechanism with the Undertow.

在大多数情况下,我们不允许所有用户访问我们的服务器。通常情况下,拥有有效凭证的用户可以获得访问权。我们可以用Undertow实现同样的机制。

To implement it, we need to create an identity manager which will check user’s authenticity for every request.

为了实现它,我们需要创建一个身份管理器,它将为每个请求检查用户的真实性。

We can use Undertow’s IdentityManager for this:

我们可以使用Undertow的IdentityManager来做这个。

public class CustomIdentityManager implements IdentityManager {
    private Map<String, char[]> users;

    // standard constructors
    
    @Override
    public Account verify(Account account) {
        return account;
    }
 
    @Override
    public Account verify(Credential credential) {
        return null;
    }
 
    @Override
    public Account verify(String id, Credential credential) {
        Account account = getAccount(id);
        if (account != null && verifyCredential(account, credential)) {
            return account;
        }
        return null;
    }
}

Once the identity manager is created, we need to create a realm which will hold the user credentials:

一旦身份管理器被创建,我们需要创建一个境界,它将保存用户的证书。

private static HttpHandler addSecurity(
  HttpHandler toWrap, 
  IdentityManager identityManager) {
 
    HttpHandler handler = toWrap;
    handler = new AuthenticationCallHandler(handler);
    handler = new AuthenticationConstraintHandler(handler);
    List<AuthenticationMechanism> mechanisms = Collections.singletonList(
      new BasicAuthenticationMechanism("Baeldung_Realm"));
    handler = new AuthenticationMechanismsHandler(handler, mechanisms);
    handler = new SecurityInitialHandler(
      AuthenticationMode.PRO_ACTIVE, identityManager, handler);
    return handler;
}

Here, we have used the AuthenticationMode as PRO_ACTIVE which means every request coming to this server will be passed to the defined authentication mechanisms to perform authentication eagerly.

在这里,我们使用了AuthenticationMode作为PRO_ACTIVE,这意味着来到这个服务器的每个请求都将被传递给定义的认证机制,以急切地执行认证。

If we define AuthenticationMode as CONSTRAINT_DRIVEN, then only those requests will go through the defined authentication mechanisms where the constraint/s that mandates authentication is triggered.

如果我们将AuthenticationMode定义为CONSTRAINT_DRIVEN,那么只有那些请求将通过所定义的认证机制,在那里触发了强制认证的约束/s。

Now, we just need to map this realm and the identity manager with the server before it starts:

现在,我们只需要在服务器启动前将这个境界和身份管理器与服务器进行映射。

public static void main(String[] args) {
    Map<String, char[]> users = new HashMap<>(2);
    users.put("root", "password".toCharArray());
    users.put("admin", "password".toCharArray());

    IdentityManager idm = new CustomIdentityManager(users);

    Undertow server = Undertow.builder().addHttpListener(8080, "localhost")
      .setHandler(addSecurity(e -> setExchange(e), idm)).build();

    server.start();
}

private static void setExchange(HttpServerExchange exchange) {
    SecurityContext context = exchange.getSecurityContext();
    exchange.getResponseSender().send("Hello " + 
      context.getAuthenticatedAccount().getPrincipal().getName(),
      IoCallback.END_EXCHANGE);
}

Here, we have created two user instances with credentials. Once the server is up, to access it, we need to use any of these two credentials.

在这里,我们已经创建了两个带有凭证的用户实例。一旦服务器启动,要访问它,我们需要使用这两个凭证中的任何一个。

3.4. Web Socket

3.4.网络套接字

It’s straightforward to create web socket exchange channel with UnderTow’s WebSocketHttpExchange API.

使用UnderTow的WebSocketHttpExchange API创建Web套接字交换通道非常简单。

For example, we can open a socket communication channel on path baeldungApp with below code snippet:

例如,我们可以用下面的代码片断在路径baeldungApp上打开一个套接字通信通道。

public static void main(String[] args) {
    Undertow server = Undertow.builder().addHttpListener(8080, "localhost")
      .setHandler(path().addPrefixPath("/baeldungApp", websocket(
        (exchange, channel) -> {
          channel.getReceiveSetter().set(getListener());
          channel.resumeReceives();
      })).addPrefixPath("/", resource(new ClassPathResourceManager(
        SocketServer.class.getClassLoader(),
        SocketServer.class.getPackage())).addWelcomeFiles("index.html")))
        .build();

    server.start();
}

private static AbstractReceiveListener getListener() {
    return new AbstractReceiveListener() {
        @Override
        protected void onFullTextMessage(WebSocketChannel channel, 
          BufferedTextMessage message) {
            String messageData = message.getData();
            for (WebSocketChannel session : channel.getPeerConnections()) {
                WebSockets.sendText(messageData, session, null);
            }
        }
    };
}

We can create an HTML page named index.html and use JavaScript’s WebSocket API to connect to this channel.

我们可以创建一个名为index.html的HTML页面,并使用JavaScript的WebSocket API来连接到这个通道。

3.5. File Server

3.5.文件服务器

With Undertow, we can also create a file server which can display directory content and directly serves files from the directory:

通过Undertow,我们还可以创建一个文件服务器,它可以显示目录内容并直接提供目录中的文件。

public static void main( String[] args ) {
    Undertow server = Undertow.builder().addHttpListener(8080, "localhost")
        .setHandler(resource(new PathResourceManager(
          Paths.get(System.getProperty("user.home")), 100 ))
        .setDirectoryListingEnabled( true ))
        .build();
    server.start();
}

We don’t need to create any UI content to display the directory contents. Out-of-the-box Undertow provides a page for this display functionality.

我们不需要创建任何UI内容来显示目录内容。开箱即用的Undertow为这种显示功能提供了一个页面。

4. Spring Boot Plugin

4.Spring Boot插件

Apart from Tomcat and Jetty, Spring Boot supports UnderTow as the embedded servlet container. To use Undertow, we need to add the following dependency in the pom.xml:

除了TomcatJetty之外,Spring Boot支持UnderTow作为嵌入式servlet容器。要使用Undertow,我们需要在pom.xml中添加以下依赖关系:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
    <version>1.5.6.RELEASE</version>
</dependency>

The latest version of Spring Boot Undertow plugin is available in Central Maven Repository.

最新版本的Spring Boot Undertow插件可在Central Maven Repository

5. Conclusion

5.结论

In this article, we learned about Undertow and how we can create different types of servers with it.

在这篇文章中,我们了解了Undertow以及我们如何用它创建不同类型的服务器。

Like always, the full source code is available over on GitHub.

像往常一样,完整的源代码可以在GitHub上找到