Einführung in JBoss Undertow

1. Übersicht

Undertow ist ein extrem leichter und leistungsstarker Webserver von JBoss . Es unterstützt sowohl blockierende als auch nicht blockierende APIs mit NIO .

Da es sich um Java handelt, kann es in allen JVM-basierten Anwendungen im eingebetteten Modus verwendet werden. Selbst der WilfFly- Server von JBoss verwendet intern Undertow , um die Leistung des Servers zu verbessern.

In diesem Tutorial zeigen wir die Funktionen von Undertow und deren Verwendung.

2. Warum unterziehen?

  • Leichtgewicht: Undertow ist mit unter 1 MB extrem leicht. Im eingebetteten Modus werden zur Laufzeit nur 4 MB Heap-Speicherplatz verwendet
  • 3.1 Servlet: Es unterstützt Servlet 3.1
  • Web Socket: Unterstützt die Web Socket-Funktionalität (einschließlich JSR-356 ).
  • Persistente Verbindung: Standardmäßig enthält Undertow persistente HTTP-Verbindungen, indem ein Keep-Alive- Antwortheader hinzugefügt wird . Es hilft Clients, die dauerhafte Verbindungen unterstützen, die Leistung zu optimieren, indem Verbindungsdetails wiederverwendet werden

3. Verwenden von Undertow

Beginnen wir mit der Verwendung von Undertow, indem wir einen einfachen Webserver erstellen.

3.1. Maven-Abhängigkeit

Um Undertow verwenden zu können , müssen wir unserer pom.xml die folgende Abhängigkeit hinzufügen :

 io.undertow undertow-servlet 1.4.18.Final 

Um ein lauffähiges Glas zu erstellen, müssen wir auch ein Maven-Shade-Plugin hinzufügen. Aus diesem Grund müssen wir auch die folgende Konfiguration hinzufügen:

 org.apache.maven.plugins maven-shade-plugin   package  shade    

Die neueste Version von Undertow ist im Central Maven Repository verfügbar.

3.2. Einfacher Server

Mit dem folgenden Codeausschnitt können wir mithilfe der Builder- API von Undertow einen einfachen Webserver erstellen :

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(); } }

Hier haben wir die Builder- API verwendet, um den 8080- Port an diesen Server zu binden . Beachten Sie außerdem, dass wir einen Lambda-Ausdruck verwendet haben, um den Handler zu verwenden.

Wir können auch das folgende Code-Snippet verwenden, um dasselbe zu tun, ohne Lambda-Ausdrücke zu verwenden:

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();

Wichtig hierbei ist die Verwendung der HttpHandler- API. Es ist das wichtigste Plugin, um eine Undertow- Anwendung an unsere Bedürfnisse anzupassen.

In diesem Fall haben wir einen benutzerdefinierten Handler hinzugefügt, der bei jeder Anforderung den Header Content-Type: text / plain response hinzufügt .

In ähnlicher Weise können wir, wenn wir bei jeder Antwort einen Standardtext zurückgeben möchten, das folgende Codefragment verwenden:

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

3.3. Sicherer Zugang

In den meisten Fällen erlauben wir nicht allen Benutzern den Zugriff auf unseren Server. Normalerweise können Benutzer mit gültigen Anmeldeinformationen Zugriff erhalten. Wir können denselben Mechanismus mit dem Undertow implementieren .

Um es zu implementieren, müssen wir einen Identitätsmanager erstellen, der die Authentizität des Benutzers für jede Anforderung überprüft.

Wir können den IdentityManager von Undertow dafür verwenden:

public class CustomIdentityManager implements IdentityManager { private Map 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; } }

Sobald der Identitätsmanager erstellt wurde, müssen wir einen Bereich erstellen, der die Benutzeranmeldeinformationen enthält:

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

Hier haben wir den AuthenticationMode als PRO_ACTIVE verwendet. Dies bedeutet, dass jede an diesen Server eingehende Anforderung an die definierten Authentifizierungsmechanismen weitergeleitet wird, um die Authentifizierung eifrig durchzuführen.

Wenn wir AuthenticationMode als CONSTRAINT_DRIVEN definieren , durchlaufen nur diese Anforderungen die definierten Authentifizierungsmechanismen, bei denen die Einschränkung (en) ausgelöst werden, die die Authentifizierung vorschreiben.

Jetzt müssen wir nur noch diesen Bereich und den Identitätsmanager dem Server zuordnen, bevor er gestartet wird:

public static void main(String[] args) { Map 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); }

Hier haben wir zwei Benutzerinstanzen mit Anmeldeinformationen erstellt. Sobald der Server hochgefahren ist, müssen wir einen dieser beiden Anmeldeinformationen verwenden, um darauf zugreifen zu können.

3.4. Web Socket

Es ist einfach, einen Web-Socket-Austauschkanal mit der WebSocketHttpExchange- API von UnderTow zu erstellen .

Zum Beispiel können wir einen Socket-Kommunikationskanal auf dem Pfad baeldungApp mit dem folgenden Code-Snippet öffnen :

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); } } }; }

Wir können eine HTML-Seite mit dem Namen index.html erstellen und die WebSocket- API von JavaScript verwenden, um eine Verbindung zu diesem Kanal herzustellen .

3.5. Dateiserver

Mit Undertow können wir auch einen Dateiserver erstellen, der Verzeichnisinhalte anzeigen und Dateien direkt aus dem Verzeichnis bereitstellen kann:

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(); }

Wir müssen keinen UI-Inhalt erstellen, um den Verzeichnisinhalt anzuzeigen. Out-of-the-Box Undertow bietet eine Seite für diese Anzeigefunktion.

4. Spring Boot Plugin

Abgesehen von Tomcat und Jetty, Frühlings - Boot unterstützt Undertow wie die eingebetteten Servlet - Container. Um Undertow verwenden zu können , müssen wir der pom.xml die folgende Abhängigkeit hinzufügen :

 org.springframework.boot spring-boot-starter-undertow 1.5.6.RELEASE 

Die neueste Version des Spring Boot Undertow-Plugins ist im Central Maven Repository verfügbar.

5. Schlussfolgerung

In diesem Artikel haben wir etwas über Undertow gelernt und wie wir damit verschiedene Servertypen erstellen können.

Wie immer ist der vollständige Quellcode auf GitHub verfügbar.