JBoss Undertowの概要
1. 概要
2. Undertowを選ぶ理由
-
軽量:Undertowは1MB未満と非常に軽量です。 埋め込みモードでは、実行時に4MBのヒープスペースしか使用しません
-
サーブレット3.1:Servlet 3.1を完全にサポート
-
Web Socket:Web Socket機能(JSR-356を含む)をサポートします
-
持続的接続:デフォルトでは、Undertowには、keep-alive応答ヘッダーを追加することでHTTP持続的接続が含まれます。 永続的な接続をサポートするクライアントが、接続の詳細を再利用してパフォーマンスを最適化するのに役立ちます
3. Undertowの使用
簡単なWebサーバーを作成して、Undertowの使用を開始しましょう。
3.1. メーベン依存
Undertowを使用するには、pom.xmlに次の依存関係を追加する必要があります。
io.undertow
undertow-servlet
1.4.18.Final
実行可能なjarを作成するには、maven-shade-pluginも追加する必要があります。 そのため、以下の構成も追加する必要があります。
org.apache.maven.plugins
maven-shade-plugin
package
shade
Undertowの最新バージョンはCentral Maven Repositoryで利用できます。
3.2. シンプルなサーバー
以下のコードスニペットを使用すると、UndertowのBuilderAPIを使用して簡単なウェブサーバーを作成できます。
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 example");
}).build();
server.start();
}
}
ここでは、Builder APIを使用して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 example");
}
}).build();
ここで注意すべき重要なことは、HttpHandlerAPIの使用法です。 It’s the most important plugin to customize an Undertow application based on our needs.
この場合、リクエストごとにContent-Type: text/plain応答ヘッダーを追加するカスタマイズされたハンドラーを追加しました。
同様に、各応答でデフォルトのテキストを返す場合は、次のコードスニペットを使用できます。
exchange.getResponseSender()
.send("Hello example");
3.3. 安全なアクセス
ほとんどの場合、すべてのユーザーがサーバーにアクセスできるわけではありません。 通常、有効な資格情報を持つユーザーがアクセスできます。Undertowを使用して同じメカニズムを実装できます。
これを実装するには、すべてのリクエストに対してユーザーの信頼性をチェックするIDマネージャーを作成する必要があります。
これには、UndertowのIdentityManagerを使用できます。
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;
}
}
IDマネージャーが作成されたら、ユーザー資格情報を保持するレルムを作成する必要があります。
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("example_Realm"));
handler = new AuthenticationMechanismsHandler(handler, mechanisms);
handler = new SecurityInitialHandler(
AuthenticationMode.PRO_ACTIVE, identityManager, handler);
return handler;
}
ここでは、AuthenticationModeをPRO_ACTIVEとして使用しました。これは、このサーバーに着信するすべての要求が、定義された認証メカニズムに渡され、認証を熱心に実行することを意味します。
AuthenticationModeをCONSTRAINT_DRIVENとして定義すると、それらの要求のみが、認証を義務付ける制約がトリガーされる定義済みの認証メカニズムを通過します。
ここで、このレルムとIDマネージャーをサーバーにマップしてから、サーバーを開始する必要があります。
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);
}
ここでは、資格情報を持つ2つのユーザーインスタンスを作成しました。 サーバーが起動したら、サーバーにアクセスするには、これら2つの資格情報のいずれかを使用する必要があります。
3.4. Webソケット
UnderTow’s WebSocketHttpExchangeAPIを使用してWebソケット交換チャネルを作成するのは簡単です。
たとえば、以下のコードスニペットを使用して、パスexampleAppでソケット通信チャネルを開くことができます。
public static void main(String[] args) {
Undertow server = Undertow.builder().addHttpListener(8080, "localhost")
.setHandler(path().addPrefixPath("/exampleApp", 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);
}
}
};
}
index.htmlという名前のHTMLページを作成し、JavaScriptのWebSocketAPIを使用してこのチャネルに接続できます。
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();
}
ディレクトリの内容を表示するためにUIコンテンツを作成する必要はありません。 すぐに使用できるUndertowは、この表示機能のページを提供します。
4. SpringBootプラグイン
TomcatとJetty,は別として、Spring Bootは組み込みサーブレットコンテナとしてUnderTowをサポートします。 Undertowを使用するには、pom.xml:に次の依存関係を追加する必要があります
org.springframework.boot
spring-boot-starter-undertow
1.5.6.RELEASE
Spring Boot Undertow pluginの最新バージョンはCentral Maven Repositoryで利用できます。
5. 結論
この記事では、Undertowと、それを使用してさまざまなタイプのサーバーを作成する方法について学習しました。
いつものように、完全なソースコードはover on GitHubで利用できます。