これは、なにをしたくて書いたもの?
QuarkusのHTTPに関する処理は、Quarkus HTTPという独立したリポジトリで作られています。
GitHub - quarkusio/quarkus-http
今回、こちらで少し遊んでみようかな、と。題材はServletです。
Quarkus HTTP
Quarkus HTTPのリポジトリは、こちら。
GitHub - quarkusio/quarkus-http
リポジトリの説明には、こう書かれています。
A Vert.x based Servlet implementation.
Vert.xをベースにしたServletの実装、ということみたいです。
いくつかのモジュールがあるようです。
サンプルもついています。
quarkus-http/examples at 4.1.7 · quarkusio/quarkus-http · GitHub
中を見るとわかるのですが、リポジトリ内の各パッケージはio.undertow
から始まるものになっています。
https://github.com/quarkusio/quarkus-http/blob/4.1.7/core/src/main/java/io/undertow/Undertow.java
このリポジトリはUndertow 3.xとなる予定だったもののようなのですが、それが明言されたissue等は見当たりませんでした。
とはいえ、Undertowは3以降ではトランスポート層をXNIOからNettyに移すことは決めていたようなので、最終的にはVert.xに
なったということなのでしょうね。
The Java network programming world has come a long way since Undertow was first started. Netty has emerged as the de-facto standard for network programming in Java, and the Undertow team has decided that the benefits of utilizing Netty outweigh any benefits in keeping our XNIO based transport layer.
Undertow 3.0 will keep Undertow’s programming model, however the underlying transport will be changed from XNIO to Netty. We will also use the Netty HTTP/1, HTTP/2 and Websocket implementations.
Undertow 3.0 Announcement · JBoss Community
そして、こちらのモジュールがQuarkusのUndertow Extension(Servletを使う時のExtension)で使われています。
https://github.com/quarkusio/quarkus-http/tree/4.1.7/servlet
<dependency> <groupId>io.quarkus.http</groupId> <artifactId>quarkus-http-servlet</artifactId> <exclusions> <exclusion> <groupId>org.jboss.spec.javax.servlet</groupId> <artifactId>jboss-servlet-api_4.0_spec</artifactId> </exclusion> <exclusion> <groupId>org.jboss.spec.javax.annotation</groupId> <artifactId>jboss-annotations-api_1.2_spec</artifactId> </exclusion> </exclusions> </dependency>
quarkus/pom.xml at 2.7.2.Final · quarkusio/quarkus · GitHub
なお、Undertow ExtensionはQuarkusを利用する時であっても、単純にRESTEasy Extensionを使うだけでは利用されません。
この場合は、Vert.xまわりのExtensionを使って駆動されます。
https://github.com/quarkusio/quarkus/tree/2.7.2.Final/extensions/vertx-http/runtime
あくまで、Undertow Extension(quarkus-undertow
)を明示的に追加した場合に利用されるものです。
そのうちWildFlyとかでも使われたりするんでしょうかね?
今回は、Quarkus HTTPのServletを簡単に試してみようと思います。
環境
今回の環境は、こちら。
$ java --version openjdk 17.0.1 2021-10-19 OpenJDK Runtime Environment (build 17.0.1+12-Ubuntu-120.04) OpenJDK 64-Bit Server VM (build 17.0.1+12-Ubuntu-120.04, mixed mode, sharing) $ mvn --version Apache Maven 3.8.4 (9b656c72d54e5bacbed989b64718c159fe39b537) Maven home: $HOME/.sdkman/candidates/maven/current Java version: 17.0.1, vendor: Private Build, runtime: /usr/lib/jvm/java-17-openjdk-amd64 Default locale: ja_JP, platform encoding: UTF-8 OS name: "linux", version: "5.4.0-100-generic", arch: "amd64", family: "unix"
準備
Maven依存関係は、こちら。
<dependencies> <dependency> <groupId>io.quarkus.http</groupId> <artifactId>quarkus-http-servlet</artifactId> <version>4.1.7</version> </dependency> <dependency> <groupId>io.quarkus.http</groupId> <artifactId>quarkus-http-vertx-backend</artifactId> <version>4.1.7</version> </dependency> </dependencies>
quarkus-http-servlet
がQuarkus HTTPのServlet実装なのですが、これを駆動するためのランタイムが必要です。
具体的には、UndertowEngine
インターフェースの実装が要求されます。
現在、Quarkus HTTPの中にはUndertowEngine
インターフェースの実装を提供しているのはquarkus-http-vertx-backend
のみで、
こちらをquarkus-http-servlet
とは別に追加します。
これで、Quarkus HTTPが提供するServletが利用できるようになります。
なお、現時点のQuarkus HTTPのServlet実装が提供する、Jakarta Servlet仕様のバージョンは4です。
https://github.com/quarkusio/quarkus-http/blob/4.1.7/pom.xml#L76
Quarkus HTTP Servletを動かす
それでは、さっそくプログラムを書いていきます。
といっても、Undertow 2.xの頃の例がそのまま動きます。
Undertow Servlet / Creating a Servlet Deployment
あとで気づきましたが、Quarkus HTTPのリポジトリにあるexampleにこのドキュメントとまったく同じ例がありました。
それはさておき、自分でも簡単なプログラムを書いてみます。
src/main/java/org/littlewings/quarkus/http/HelloServlet.java
package org.littlewings.quarkus.http; import java.io.IOException; import java.util.Optional; import java.util.concurrent.TimeUnit; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { String message = Optional.ofNullable(req.getParameter("message")).orElse("World"); res.getWriter().write(String.format("Hello %s!!", message)); } }
mainクラス。
src/main/java/org/littlewings/quarkus/http/App.java
package org.littlewings.quarkus.http; import javax.servlet.ServletException; import io.undertow.Handlers; import io.undertow.Undertow; import io.undertow.server.handlers.PathHandler; import io.undertow.servlet.Servlets; import io.undertow.servlet.api.DeploymentInfo; import io.undertow.servlet.api.DeploymentManager; import org.jboss.logging.Logger; public class App { public static void main(String... args) throws ServletException { Logger logger = Logger.getLogger(App.class); DeploymentInfo servletBuilder = Servlets .deployment() .setClassLoader(App.class.getClassLoader()) .setContextPath("/") .setDeploymentName("myapp") .addServlets( Servlets .servlet("HelloServlert", HelloServlet.class) .addMapping("/hello") ); DeploymentManager manager = Servlets .defaultContainer() .addDeployment(servletBuilder); manager.deploy(); PathHandler handler = Handlers .path(Handlers.redirect("/")) .addPrefixPath("/", manager.start()); Undertow server = Undertow .builder() .addHttpListener(8080, "0.0.0.0") .setHandler(handler) .build(); server.start(); logger.info("start server."); } }
起動。
$ mvn compile exec:java -Dexec.mainClass=org.littlewings.quarkus.http.App
確認。
$ curl localhost:8080/hello Hello World!! $ curl localhost:8080/hello?message=Quarkus Hello Quarkus!!
OKそうですね。
オマケ
見た目はUndertow 2.xを使っている時とまったく変わらないので、Quarkus HTTPを使っている感じがしません。
実際、以前のUndertow 3.xについて書いているブログにも、Servlet APIを使っている分には変化には気づかないかもと書かれて
いますしね。
If you are using the Servlet API then you will likely not notice any change. You will need some different dependencies (Netty instead of XNIO), however the rest of the experience should be mostly identical If you are using the low level Undertow HttpHandler and HttpServerExchange then you will need to migrate your application. For the most part this migration should be straightforward, as most concepts from the old API directly map to the new API.
Undertow 3.0 Announcement · JBoss Community
なお、スレッドまわりについては接続の受け付けはVert.xのイベントループスレッド(IOスレッド)ですが、リクエストを処理するのは
ワーカースレッド(ブロッキング処理用のスレッド)になります。
ワーカースレッドは、デフォルトだとworkerThreads
で指定された数でExecutors#newFixedThreadPool
で作成された
スレッドプールが利用されます。
まとめ
Quarkus HTTPでServletを使ってみました。ほぼ、Undertow 2.xのままでしたね。
ここまで変わらないようだと、この上でRESTEasyを動かしたりしたくなるものですが…。
※RESTEasy Reactiveを動かすのは、ちょっと難しそうです…