«1. Обзор
Undertow — чрезвычайно легкий и высокопроизводительный веб-сервер от JBoss. Он поддерживает как блокирующие, так и неблокирующие API с NIO.
Поскольку он написан на Java, его можно использовать в любых приложениях на основе JVM во встроенном режиме, даже сервер JBoss WilfFly внутри использует Undertow для повышения производительности сервера.
В этом уроке мы покажем возможности Undertow и как его использовать.
2. Почему Отлив?
-
Легкий: Undertow чрезвычайно легкий — менее 1 МБ. Во встроенном режиме он использует только 4 МБ пространства кучи во время выполнения. Сервлет 3.1: полностью поддерживает сервлет 3.1. Веб-сокет: поддерживает функции веб-сокета (включая JSR-356). заголовок живого ответа. Это помогает клиентам, поддерживающим постоянные соединения, оптимизировать производительность за счет повторного использования сведений о соединении
3. Использование Undertow
Давайте начнем использовать Undertow, создав простой веб-сервер.
3.1. Зависимость Maven
Чтобы использовать Undertow, нам нужно добавить следующую зависимость в наш pom.xml:
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-servlet</artifactId>
<version>1.4.18.Final</version>
</dependency>
Чтобы создать исполняемый jar, нам также нужно добавить maven-shade-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>
Последняя версия Undertow доступна в центральном репозитории Maven.
3.2. Простой сервер
С помощью приведенного ниже фрагмента кода мы можем создать простой веб-сервер, используя API-интерфейс Undertow Builder:
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();
}
}
Здесь мы использовали API-интерфейс Builder для привязки порта 8080 к этому серверу. Также обратите внимание, что мы использовали лямбда-выражение для использования обработчика.
Мы также можем использовать приведенный ниже фрагмент кода, чтобы сделать то же самое без использования лямбда-выражений:
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();
Здесь важно отметить использование HttpHandler API. Это самый важный плагин для настройки приложения Undertow в соответствии с нашими потребностями.
В этом случае мы добавили настраиваемый обработчик, который будет добавлять заголовок ответа Content-Type: text/plain к каждому запросу.
Аналогичным образом, если мы хотим возвращать некоторый текст по умолчанию с каждым ответом, мы можем использовать приведенный ниже фрагмент кода:
exchange.getResponseSender()
.send("Hello Baeldung");
3.3. Безопасный доступ
В большинстве случаев мы не разрешаем всем пользователям доступ к нашему серверу. Обычно доступ могут получить пользователи с действительными учетными данными. Мы можем реализовать тот же механизм с Undertow.
Чтобы реализовать это, нам нужно создать менеджер удостоверений, который будет проверять подлинность пользователя для каждого запроса.
Для этого мы можем использовать IdentityManager Undertow:
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;
}
}
После создания диспетчера идентификации нам нужно создать область, в которой будут храниться учетные данные пользователя:
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;
}
Здесь мы использовали AuthenticationMode как PRO_ACTIVE, что означает, что каждый запрос, поступающий на этот сервер, будет передан определенным механизмам аутентификации для выполнения аутентификации с готовностью.
Если мы определим AuthenticationMode как CONSTRAINT_DRIVEN, то только те запросы будут проходить через определенные механизмы аутентификации, где срабатывает ограничение(я), которое требует аутентификацию.
Теперь нам просто нужно сопоставить эту область и диспетчер удостоверений с сервером перед его запуском:
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);
}
Здесь мы создали два пользовательских экземпляра с учетными данными. Когда сервер запущен, для доступа к нему нам нужно использовать любой из этих двух учетных данных.
3.4. Веб-сокет
Создать канал обмена веб-сокетами с помощью API WebSocketHttpExchange от UnderTow очень просто.
Например, мы можем открыть коммуникационный канал сокета по пути 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);
}
}
};
}
Мы можем создать HTML-страницу с именем index.html и использовать JavaScript WebSocket API для подключения к этому каналу.
3.5. Файловый сервер
С помощью 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();
}
Нам не нужно создавать какой-либо пользовательский интерфейс для отображения содержимого каталога. Стандартный Undertow предоставляет страницу для этой функции отображения.
4. Плагин загрузки Spring
«Помимо Tomcat и Jetty, Spring Boot поддерживает UnderTow в качестве встроенного контейнера сервлетов. Чтобы использовать Undertow, нам нужно добавить следующую зависимость в pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
<version>1.5.6.RELEASE</version>
</dependency>
Последняя версия плагина Spring Boot Undertow доступна в центральном репозитории Maven.
5. Заключение
В этой статье мы узнали о Undertow и о том, как с его помощью можно создавать различные типы серверов.
Как всегда, полный исходный код доступен на GitHub.