これは、なにをしたくて書いたもの?
最近Quarkusを触っていなかったのですが、少し前にRESTEasyのバックエンドがUndertowからVert.xに移ったという話を見たので、
1度見ておこうかなと。
Quarkus 0.24.0 released - Vert.x everywhere
Quarkus 0.23.2 released - Back on track
Quarkus 0.23.1 released - Paving the way to our new HTTP layer
0.24.0で完全に移行していて、0.23.1から移り始めていたんですね。2019年9月の話ですねぇ。
久しぶりに、ちょっと試してみましょう。
環境
今回の環境は、こちら。
$ java -version openjdk version "1.8.0_232" OpenJDK Runtime Environment (build 1.8.0_232-8u232-b09-0ubuntu1~18.04.1-b09) OpenJDK 64-Bit Server VM (build 25.232-b09, mixed mode) $ $GRAALVM_HOME/bin/native-image --version GraalVM Version 19.2.1 CE $ mvn --version Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f) Maven home: $HOME/.sdkman/candidates/maven/current Java version: 1.8.0_232, vendor: Private Build, runtime: /usr/lib/jvm/java-8-openjdk-amd64/jre Default locale: ja_JP, platform encoding: UTF-8 OS name: "linux", version: "4.15.0-74-generic", arch: "amd64", family: "unix"
サンプルプロジェクト
今回は、RESTEasy+JSON(Jackson)な構成でいきましょう。
プロジェクトの作成。今回使用するQuarkusのバージョンは、1.1.1.Finalです。
$ mvn io.quarkus:quarkus-maven-plugin:1.1.1.Final:create \ -DprojectGroupId=org.littlewings \ -DprojectArtifactId=resteasy-vertx-jackson \ -Dextensions="resteasy-jackson"
作成されたディレクトリに移動。
$ cd resteasy-vertx-jackson
pom.xmlに書かれた依存関係は、こんな感じです。
<dependencies> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-resteasy</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-junit5</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.rest-assured</groupId> <artifactId>rest-assured</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-resteasy-jackson</artifactId> </dependency> </dependencies>
Mavenで依存関係を見てみましょう。
$ mvn dependency:tree
こんな感じの結果に。
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ resteasy-vertx-jackson --- [INFO] org.littlewings:resteasy-vertx-jackson:jar:1.0-SNAPSHOT [INFO] +- io.quarkus:quarkus-resteasy:jar:1.1.1.Final:compile [INFO] | +- io.quarkus:quarkus-vertx-http:jar:1.1.1.Final:compile [INFO] | | +- io.quarkus.security:quarkus-security:jar:1.0.1.Final:compile [INFO] | | +- jakarta.enterprise:jakarta.enterprise.cdi-api:jar:2.0.2:compile [INFO] | | | +- jakarta.el:jakarta.el-api:jar:3.0.3:compile [INFO] | | | \- jakarta.interceptor:jakarta.interceptor-api:jar:1.2.5:compile [INFO] | | +- io.quarkus:quarkus-vertx-core:jar:1.1.1.Final:compile [INFO] | | | +- io.quarkus:quarkus-netty:jar:1.1.1.Final:compile [INFO] | | | | +- io.netty:netty-codec:jar:4.1.42.Final:compile [INFO] | | | | \- io.netty:netty-handler:jar:4.1.42.Final:compile [INFO] | | | \- io.vertx:vertx-core:jar:3.8.4:compile [INFO] | | | +- io.netty:netty-common:jar:4.1.42.Final:compile [INFO] | | | +- io.netty:netty-buffer:jar:4.1.42.Final:compile [INFO] | | | +- io.netty:netty-transport:jar:4.1.42.Final:compile [INFO] | | | +- io.netty:netty-handler-proxy:jar:4.1.42.Final:compile [INFO] | | | | \- io.netty:netty-codec-socks:jar:4.1.42.Final:compile [INFO] | | | +- io.netty:netty-codec-http:jar:4.1.42.Final:compile [INFO] | | | +- io.netty:netty-codec-http2:jar:4.1.42.Final:compile [INFO] | | | +- io.netty:netty-resolver:jar:4.1.42.Final:compile [INFO] | | | \- io.netty:netty-resolver-dns:jar:4.1.42.Final:compile [INFO] | | | \- io.netty:netty-codec-dns:jar:4.1.42.Final:compile [INFO] | | \- io.vertx:vertx-web:jar:3.8.4:compile [INFO] | | +- io.vertx:vertx-web-common:jar:3.8.4:compile [INFO] | | +- io.vertx:vertx-auth-common:jar:3.8.4:compile [INFO] | | \- io.vertx:vertx-bridge-common:jar:3.8.4:compile [INFO] | \- io.quarkus:quarkus-resteasy-server-common:jar:1.1.1.Final:compile [INFO] | +- io.quarkus:quarkus-arc:jar:1.1.1.Final:compile [INFO] | | +- io.quarkus.arc:arc:jar:1.1.1.Final:compile [INFO] | | \- org.eclipse.microprofile.context-propagation:microprofile-context-propagation-api:jar:1.0.1:compile [INFO] | +- io.quarkus:quarkus-resteasy-common:jar:1.1.1.Final:compile [INFO] | | +- org.jboss.resteasy:resteasy-core:jar:4.4.1.Final:compile [INFO] | | | +- org.jboss.spec.javax.ws.rs:jboss-jaxrs-api_2.1_spec:jar:2.0.1.Final:compile [INFO] | | | +- org.jboss.resteasy:resteasy-core-spi:jar:4.4.1.Final:compile [INFO] | | | +- org.reactivestreams:reactive-streams:jar:1.0.3:compile [INFO] | | | \- org.eclipse.microprofile.config:microprofile-config-api:jar:1.3:compile [INFO] | | \- com.sun.activation:jakarta.activation:jar:1.2.1:compile [INFO] | \- jakarta.validation:jakarta.validation-api:jar:2.0.2:compile [INFO] +- io.quarkus:quarkus-junit5:jar:1.1.1.Final:test [INFO] | +- io.quarkus:quarkus-bootstrap-core:jar:1.1.1.Final:test [INFO] | | +- com.google.guava:guava:jar:27.0.1-jre:compile [INFO] | | | +- com.google.guava:failureaccess:jar:1.0.1:compile [INFO] | | | +- com.google.guava:listenablefuture:jar:9999.0-empty-to-avoid-conflict-with-guava:compile [INFO] | | | +- com.google.code.findbugs:jsr305:jar:3.0.2:compile [INFO] | | | +- org.checkerframework:checker-qual:jar:2.5.2:compile [INFO] | | | +- com.google.errorprone:error_prone_annotations:jar:2.2.0:compile [INFO] | | | +- com.google.j2objc:j2objc-annotations:jar:1.1:compile [INFO] | | | \- org.codehaus.mojo:animal-sniffer-annotations:jar:1.17:compile [INFO] | | +- org.apache.commons:commons-lang3:jar:3.9:test [INFO] | | +- org.apache.maven:maven-embedder:jar:3.5.4:test [INFO] | | | +- org.apache.maven:maven-settings:jar:3.5.4:test [INFO] | | | +- org.apache.maven:maven-core:jar:3.5.4:test [INFO] | | | | \- org.apache.maven:maven-artifact:jar:3.5.4:test [INFO] | | | +- org.apache.maven:maven-plugin-api:jar:3.5.4:test [INFO] | | | +- org.apache.maven:maven-model:jar:3.5.4:test [INFO] | | | +- org.apache.maven:maven-model-builder:jar:3.5.4:test [INFO] | | | +- org.apache.maven:maven-builder-support:jar:3.5.4:test [INFO] | | | +- org.apache.maven.resolver:maven-resolver-api:jar:1.1.1:test [INFO] | | | +- org.apache.maven.resolver:maven-resolver-util:jar:1.1.1:test [INFO] | | | +- org.apache.maven.shared:maven-shared-utils:jar:3.2.1:test [INFO] | | | | \- commons-io:commons-io:jar:2.6:test [INFO] | | | +- com.google.inject:guice:jar:no_aop:4.2.0:test [INFO] | | | | \- aopalliance:aopalliance:jar:1.0:test [INFO] | | | +- org.codehaus.plexus:plexus-utils:jar:3.0.24:test [INFO] | | | +- org.codehaus.plexus:plexus-classworlds:jar:2.5.2:test [INFO] | | | +- org.eclipse.sisu:org.eclipse.sisu.plexus:jar:0.3.3:test [INFO] | | | +- org.codehaus.plexus:plexus-component-annotations:jar:1.7.1:test [INFO] | | | \- commons-cli:commons-cli:jar:1.4:test [INFO] | | +- jakarta.annotation:jakarta.annotation-api:jar:1.3.5:compile [INFO] | | +- jakarta.inject:jakarta.inject-api:jar:1.0:compile [INFO] | | +- org.apache.maven:maven-settings-builder:jar:3.5.4:test [INFO] | | | +- org.codehaus.plexus:plexus-interpolation:jar:1.24:test [INFO] | | | \- org.sonatype.plexus:plexus-sec-dispatcher:jar:1.4:test [INFO] | | | \- org.sonatype.plexus:plexus-cipher:jar:1.4:test [INFO] | | +- org.apache.maven:maven-resolver-provider:jar:3.5.4:test [INFO] | | | +- org.apache.maven:maven-repository-metadata:jar:3.5.4:test [INFO] | | | +- org.apache.maven.resolver:maven-resolver-spi:jar:1.1.1:test [INFO] | | | \- org.apache.maven.resolver:maven-resolver-impl:jar:1.1.1:test [INFO] | | +- org.apache.maven.resolver:maven-resolver-connector-basic:jar:1.1.1:test [INFO] | | +- org.apache.maven.resolver:maven-resolver-transport-wagon:jar:1.1.1:test [INFO] | | | \- org.apache.maven.wagon:wagon-provider-api:jar:3.0.0:test [INFO] | | +- org.apache.maven.wagon:wagon-http:jar:3.0.0:test [INFO] | | | \- org.apache.maven.wagon:wagon-http-shared:jar:3.0.0:test [INFO] | | | \- org.jsoup:jsoup:jar:1.7.2:test [INFO] | | +- org.apache.maven.wagon:wagon-file:jar:3.0.0:test [INFO] | | +- org.jboss.logging:jboss-logging:jar:3.3.2.Final:compile [INFO] | | \- org.jboss.logging:commons-logging-jboss-logging:jar:1.0.0.Final:test [INFO] | +- io.quarkus:quarkus-test-common:jar:1.1.1.Final:test [INFO] | | +- io.quarkus:quarkus-core-deployment:jar:1.1.1.Final:test [INFO] | | | +- io.quarkus.gizmo:gizmo:jar:1.0.0.Final:test [INFO] | | | | \- org.ow2.asm:asm-util:jar:7.1:test [INFO] | | | | +- org.ow2.asm:asm-tree:jar:7.1:test [INFO] | | | | \- org.ow2.asm:asm-analysis:jar:7.1:test [INFO] | | | +- org.ow2.asm:asm:jar:7.1:test [INFO] | | | \- io.quarkus:quarkus-builder:jar:1.1.1.Final:test [INFO] | | +- io.quarkus:quarkus-jsonp-deployment:jar:1.1.1.Final:test [INFO] | | | \- io.quarkus:quarkus-jsonp:jar:1.1.1.Final:test [INFO] | | | \- org.glassfish:jakarta.json:jar:1.1.6:test [INFO] | | \- org.jboss:jandex:jar:2.1.2.Final:test [INFO] | +- org.junit.jupiter:junit-jupiter:jar:5.5.2:test [INFO] | | +- org.junit.jupiter:junit-jupiter-api:jar:5.5.2:test [INFO] | | | +- org.apiguardian:apiguardian-api:jar:1.1.0:test [INFO] | | | +- org.opentest4j:opentest4j:jar:1.2.0:test [INFO] | | | \- org.junit.platform:junit-platform-commons:jar:1.5.2:test [INFO] | | +- org.junit.jupiter:junit-jupiter-params:jar:5.5.2:test [INFO] | | \- org.junit.jupiter:junit-jupiter-engine:jar:5.5.2:test [INFO] | | \- org.junit.platform:junit-platform-engine:jar:1.5.2:test [INFO] | \- io.quarkus:quarkus-core:jar:1.1.1.Final:compile [INFO] | +- io.smallrye.config:smallrye-config:jar:1.5.1:compile [INFO] | | \- io.smallrye.config:smallrye-config-common:jar:1.5.1:compile [INFO] | +- org.jboss.logmanager:jboss-logmanager-embedded:jar:1.0.4:compile [INFO] | +- org.jboss.logging:jboss-logging-annotations:jar:2.1.0.Final:compile [INFO] | +- org.jboss.threads:jboss-threads:jar:3.0.0.Final:compile [INFO] | +- org.slf4j:slf4j-api:jar:1.7.29:compile [INFO] | +- org.jboss.slf4j:slf4j-jboss-logging:jar:1.2.0.Final:compile [INFO] | +- org.graalvm.sdk:graal-sdk:jar:19.2.1:compile [INFO] | \- org.wildfly.common:wildfly-common:jar:1.5.0.Final-format-001:compile [INFO] +- io.rest-assured:rest-assured:jar:4.1.2:test [INFO] | +- org.codehaus.groovy:groovy:jar:2.5.8:test [INFO] | +- org.codehaus.groovy:groovy-xml:jar:2.5.8:test [INFO] | +- org.apache.httpcomponents:httpclient:jar:4.5.10:test [INFO] | | +- org.apache.httpcomponents:httpcore:jar:4.4.12:test [INFO] | | \- commons-codec:commons-codec:jar:1.13:test [INFO] | +- org.apache.httpcomponents:httpmime:jar:4.5.3:test [INFO] | +- org.hamcrest:hamcrest:jar:2.1:test [INFO] | +- org.ccil.cowan.tagsoup:tagsoup:jar:1.2.1:test [INFO] | +- io.rest-assured:json-path:jar:4.1.2:test [INFO] | | +- org.codehaus.groovy:groovy-json:jar:2.5.8:test [INFO] | | \- io.rest-assured:rest-assured-common:jar:4.1.2:test [INFO] | \- io.rest-assured:xml-path:jar:4.1.2:test [INFO] | +- javax.xml.bind:jaxb-api:jar:2.3.1:test [INFO] | \- org.apache.sling:org.apache.sling.javax.activation:jar:0.1.0:test [INFO] \- io.quarkus:quarkus-resteasy-jackson:jar:1.1.1.Final:compile [INFO] +- io.quarkus:quarkus-jackson:jar:1.1.1.Final:compile [INFO] | +- com.fasterxml.jackson.core:jackson-databind:jar:2.9.10.2:compile [INFO] | +- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.9.10:compile [INFO] | +- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:jar:2.9.10:compile [INFO] | \- com.fasterxml.jackson.module:jackson-module-parameter-names:jar:2.9.10:compile [INFO] +- org.jboss.resteasy:resteasy-jackson2-provider:jar:4.4.1.Final:compile [INFO] | +- org.jboss.resteasy:resteasy-jaxb-provider:jar:4.4.1.Final:compile [INFO] | | \- org.glassfish.jaxb:jaxb-runtime:jar:2.3.3-b01:compile [INFO] | | +- org.glassfish.jaxb:txw2:jar:2.3.3-b01:compile [INFO] | | \- com.sun.istack:istack-commons-runtime:jar:3.0.10:compile [INFO] | +- com.fasterxml.jackson.core:jackson-core:jar:2.9.10:compile [INFO] | +- com.fasterxml.jackson.core:jackson-annotations:jar:2.9.10:compile [INFO] | +- com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:jar:2.9.10:compile [INFO] | | +- com.fasterxml.jackson.jaxrs:jackson-jaxrs-base:jar:2.9.10:compile [INFO] | | \- com.fasterxml.jackson.module:jackson-module-jaxb-annotations:jar:2.9.10:compile [INFO] | \- com.github.fge:json-patch:jar:1.9:compile [INFO] | \- com.github.fge:jackson-coreutils:jar:1.6:compile [INFO] | \- com.github.fge:msg-simple:jar:1.1:compile [INFO] | \- com.github.fge:btf:jar:1.2:compile [INFO] \- org.jboss.spec.javax.xml.bind:jboss-jaxb-api_2.3_spec:jar:2.0.0.Final:compile
RESTEasyまわりを見ると、確かにUndertowがいません。Vert.xとNettyが見えます。
[INFO] +- io.quarkus:quarkus-resteasy:jar:1.1.1.Final:compile [INFO] | +- io.quarkus:quarkus-vertx-http:jar:1.1.1.Final:compile [INFO] | | +- io.quarkus.security:quarkus-security:jar:1.0.1.Final:compile [INFO] | | +- jakarta.enterprise:jakarta.enterprise.cdi-api:jar:2.0.2:compile [INFO] | | | +- jakarta.el:jakarta.el-api:jar:3.0.3:compile [INFO] | | | \- jakarta.interceptor:jakarta.interceptor-api:jar:1.2.5:compile [INFO] | | +- io.quarkus:quarkus-vertx-core:jar:1.1.1.Final:compile [INFO] | | | +- io.quarkus:quarkus-netty:jar:1.1.1.Final:compile [INFO] | | | | +- io.netty:netty-codec:jar:4.1.42.Final:compile [INFO] | | | | \- io.netty:netty-handler:jar:4.1.42.Final:compile [INFO] | | | \- io.vertx:vertx-core:jar:3.8.4:compile [INFO] | | | +- io.netty:netty-common:jar:4.1.42.Final:compile [INFO] | | | +- io.netty:netty-buffer:jar:4.1.42.Final:compile [INFO] | | | +- io.netty:netty-transport:jar:4.1.42.Final:compile [INFO] | | | +- io.netty:netty-handler-proxy:jar:4.1.42.Final:compile [INFO] | | | | \- io.netty:netty-codec-socks:jar:4.1.42.Final:compile [INFO] | | | +- io.netty:netty-codec-http:jar:4.1.42.Final:compile [INFO] | | | +- io.netty:netty-codec-http2:jar:4.1.42.Final:compile [INFO] | | | +- io.netty:netty-resolver:jar:4.1.42.Final:compile [INFO] | | | \- io.netty:netty-resolver-dns:jar:4.1.42.Final:compile [INFO] | | | \- io.netty:netty-codec-dns:jar:4.1.42.Final:compile [INFO] | | \- io.vertx:vertx-web:jar:3.8.4:compile [INFO] | | +- io.vertx:vertx-web-common:jar:3.8.4:compile [INFO] | | +- io.vertx:vertx-auth-common:jar:3.8.4:compile [INFO] | | \- io.vertx:vertx-bridge-common:jar:3.8.4:compile [INFO] | \- io.quarkus:quarkus-resteasy-server-common:jar:1.1.1.Final:compile [INFO] | +- io.quarkus:quarkus-arc:jar:1.1.1.Final:compile [INFO] | | +- io.quarkus.arc:arc:jar:1.1.1.Final:compile [INFO] | | \- org.eclipse.microprofile.context-propagation:microprofile-context-propagation-api:jar:1.0.1:compile [INFO] | +- io.quarkus:quarkus-resteasy-common:jar:1.1.1.Final:compile [INFO] | | +- org.jboss.resteasy:resteasy-core:jar:4.4.1.Final:compile [INFO] | | | +- org.jboss.spec.javax.ws.rs:jboss-jaxrs-api_2.1_spec:jar:2.0.1.Final:compile [INFO] | | | +- org.jboss.resteasy:resteasy-core-spi:jar:4.4.1.Final:compile [INFO] | | | +- org.reactivestreams:reactive-streams:jar:1.0.3:compile [INFO] | | | \- org.eclipse.microprofile.config:microprofile-config-api:jar:1.3:compile [INFO] | | \- com.sun.activation:jakarta.activation:jar:1.2.1:compile [INFO] | \- jakarta.validation:jakarta.validation-api:jar:2.0.2:compile
というか、Servletすらいないじゃないですか。JAX-RSのSpecは、さすがにいますね。
今回は、書籍をお題にコードを書いてみます。
書籍クラス。
src/main/java/org/littlewings/quarkus/resteasy/Book.java
package org.littlewings.quarkus.resteasy; public class Book { private String isbn; private String title; private int price; // getter/setterは省略 }
JAX-RSリソースクラス。
src/main/java/org/littlewings/quarkus/resteasy/BookResource.java
package org.littlewings.quarkus.resteasy; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; @Path("book") public class BookResource { Map<String, Book> books = new ConcurrentHashMap<>(); @GET @Produces(MediaType.APPLICATION_JSON) public List<Book> books() { return new ArrayList<>(books.values()); } @GET @Path("{isbn}") @Produces(MediaType.APPLICATION_JSON) public Book find(@PathParam("isbn") String isbn) { return books.get(isbn); } @PUT @Path("{isbn}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Response create(Book book, @Context UriInfo uriInfo) { books.put(book.getIsbn(), book); return Response.created(uriInfo.getRequestUriBuilder().build()).build(); } }
パッケージングして、
$ mvn package
起動。
$ java -jar target/resteasy-vertx-jackson-1.0-SNAPSHOT-runner.jar
認識しているExtensionに、Servletはいません。
2020-01-25 19:11:45,900 INFO [io.quarkus] (main) Installed features: [cdi, resteasy, resteasy-jackson]
データの登録。
$ curl -i -XPUT -H 'Content-Type: application/json' http://localhost:8080/book/978-4774183169 -d '{"isbn": "978-4774183169", "title": "パーフェクト Java EE", "price": 3456}' HTTP/1.1 201 Created Content-Length: 0 Location: http://localhost:8080/book/978-4774183169 $ curl -i -XPUT -H 'Content-Type: application/json' http://localhost:8080/book/978-4798124605 -d '{"isbn": "978-4798124605", "title": "Beginning Java EE 6", "price": 3891}' HTTP/1.1 201 Created Content-Length: 0 Location: http://localhost:8080/book/978-4798124605 $ curl -i -XPUT -H 'Content-Type: application/json' http://localhost:8080/book/978-4798140926 -d '{"isbn": "978-4798140926", "title": "Java EE 7徹底入門", "price": 4104}' HTTP/1.1 201 Created Content-Length: 0 Location: http://localhost:8080/book/978-4798140926
データの取得。
$ curl -s http://localhost:8080/book/978-4774183169 | jq { "isbn": "978-4774183169", "title": "パーフェクト Java EE", "price": 3456 } $ curl -s localhost:8080/book | jq [ { "isbn": "978-4798124605", "title": "Beginning Java EE 6", "price": 3891 }, { "isbn": "978-4798140926", "title": "Java EE 7徹底入門", "price": 4104 }, { "isbn": "978-4774183169", "title": "パーフェクト Java EE", "price": 3456 } ]
ネイティブイメージにしても結果は同じなので、割愛。
$ mvn -P native package
Servlet APIの代わりや、スレッドの情報を見る
ところで、ここまでだと特に面白味がないので、HttpServletRequest代わりの情報とかどうしたらいいんだろう?というところだと、
RESTEasyのSPIを使うみたいです。
HttpRequest (RESTEasy JAX-RS 4.4.1.Final API)
あと、スレッドの情報とか気になったりします。
というわけで、こんなJAX-RSリソースクラスを使って確認。
src/main/java/org/littlewings/quarkus/resteasy/HttpRequestResource.java
package org.littlewings.quarkus.resteasy; import java.util.LinkedHashMap; import java.util.Map; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import org.jboss.logging.Logger; import org.jboss.resteasy.spi.HttpRequest; @Path("http-request") public class HttpRequestResource { Logger logger = Logger.getLogger(HttpRequestResource.class); @GET @Path("print-request") @Produces(MediaType.APPLICATION_JSON) public Map<String, Object> printRequest(@Context HttpRequest request) { Map<String, Object> response = new LinkedHashMap<>(); response.put("method", request.getHttpMethod()); response.put("request-uri", request.getUri().getRequestUri().toString()); response.put("path", request.getUri().getPath()); response.put("query", request.getUri().getRequestUri().getQuery()); return response; } @GET @Path("thread-dump") @Produces(MediaType.TEXT_PLAIN) public String printThreadDump() { logger.infof("Thread[%s / %s]", Thread.currentThread().getName(), Thread.currentThread().getClass().getName()); Thread.dumpStack(); return "print Thread Dump"; } }
確認。
$ curl -s localhost:8080/http-request/print-request?param=hoge | jq { "method": "GET", "request-uri": "http://localhost:8080/http-request/print-request?param=hoge", "path": "/http-request/print-request", "query": "param=hoge" } $ curl -s http://localhost:8080/http-request/thread-dump print Thread Dump
スレッドダンプは、こんな感じでした。
2020-01-25 19:12:04,117 INFO [org.lit.qua.res.HttpRequestResource] (executor-thread-1) Thread[executor-thread-1 / org.jboss.threads.JBossThread] java.lang.Exception: Stack trace at java.lang.Thread.dumpStack(Thread.java:1336) at org.littlewings.quarkus.resteasy.HttpRequestResource.printThreadDump(HttpRequestResource.java:38) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:151) at org.jboss.resteasy.core.MethodInjectorImpl.lambda$invoke$3(MethodInjectorImpl.java:122) at java.util.concurrent.CompletableFuture.uniApply(CompletableFuture.java:616) at java.util.concurrent.CompletableFuture.uniApplyStage(CompletableFuture.java:628) at java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:1996) at java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:110) at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:122) at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:594) at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:468) at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:421) at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:363) at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:423) at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:391) at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invoke$1(ResourceMethodInvoker.java:365) at java.util.concurrent.CompletableFuture.uniComposeStage(CompletableFuture.java:995) at java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:2137) at java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:110) at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:365) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:477) at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:252) at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:153) at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:363) at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:156) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:238) at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73) at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:120) at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.access$000(VertxRequestHandler.java:36) at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler$1.run(VertxRequestHandler.java:85) at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35) at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2011) at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1535) at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1426) at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29) at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29) at java.lang.Thread.run(Thread.java:748) at org.jboss.threads.JBossThread.run(JBossThread.java:479)
スレッドプールの情報を追うと、このあたりのようです。
quarkus/ExecutorRecorder.java at 1.1.1.Final · quarkusio/quarkus · GitHub
https://quarkus.io/guides/all-config#quarkus-core_quarkus.thread-pool.core-threads
他のバージョンだと、Vert.xのスレッドプールで調整しているようだったので、バージョンごとにだいぶ変わるんですねぇ…。
なお、ネイティブイメージの時のスタックトレースは、こんな感じでした。
2020-01-25 19:12:49,917 INFO [org.lit.qua.res.HttpRequestResource] (executor-thread-1) Thread[executor-thread-1 / org.jboss.threads.JBossThread] java.lang.Exception: Stack trace at java.lang.Thread.dumpStack(Thread.java:1336) at org.littlewings.quarkus.resteasy.HttpRequestResource.printThreadDump(HttpRequestResource.java:38) at java.lang.reflect.Method.invoke(Method.java:498) at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:151) at org.jboss.resteasy.core.MethodInjectorImpl.lambda$invoke$3(MethodInjectorImpl.java:122) at java.util.concurrent.CompletableFuture.uniApply(CompletableFuture.java:616) at java.util.concurrent.CompletableFuture.uniApplyStage(CompletableFuture.java:628) at java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:1996) at java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:110) at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:122) at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:594) at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:468) at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:421) at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:363) at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:423) at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:391) at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invoke$1(ResourceMethodInvoker.java:365) at java.util.concurrent.CompletableFuture.uniComposeStage(CompletableFuture.java:995) at java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:2137) at java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:110) at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:365) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:477) at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:252) at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:153) at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:363) at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:156) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:238) at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73) at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:120) at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.access$000(VertxRequestHandler.java:36) at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler$1.run(VertxRequestHandler.java:85) at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35) at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2011) at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1535) at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1395) at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29) at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29) at java.lang.Thread.run(Thread.java:748) at org.jboss.threads.JBossThread.run(JBossThread.java:479) at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:460) at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:193)
ここが増えてますね。
at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:460) at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:193)
Servlet APIを使う
RESTEasyのバックエンドを、Vert.xではなくUndertowにするには、Undertow Extensionを追加します。
$ mvn quarkus:add-extension -Dextensions=quarkus-undertow
依存関係に、こちらが追加されます。
<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-undertow</artifactId> </dependency>
「mvn dependency:tree」で依存関係を見ると、Servlet APIは追加されるものの、その背後にいるのはVert.xですね。
[INFO] \- io.quarkus:quarkus-undertow:jar:1.1.1.Final:compile [INFO] +- io.quarkus:quarkus-arc:jar:1.1.1.Final:compile [INFO] | \- io.quarkus.arc:arc:jar:1.1.1.Final:compile [INFO] +- io.quarkus.security:quarkus-security:jar:1.0.1.Final:compile [INFO] +- jakarta.enterprise:jakarta.enterprise.cdi-api:jar:2.0.2:compile [INFO] | +- jakarta.el:jakarta.el-api:jar:3.0.3:compile [INFO] | \- jakarta.interceptor:jakarta.interceptor-api:jar:1.2.5:compile [INFO] +- io.quarkus.http:quarkus-http-servlet:jar:3.0.1.Final:compile [INFO] +- jakarta.servlet:jakarta.servlet-api:jar:4.0.3:compile [INFO] +- jakarta.annotation:jakarta.annotation-api:jar:1.3.5:compile [INFO] +- io.quarkus.http:quarkus-http-vertx-backend:jar:3.0.1.Final:compile [INFO] | +- io.vertx:vertx-core:jar:3.8.4:compile [INFO] | | +- io.netty:netty-common:jar:4.1.42.Final:compile [INFO] | | +- io.netty:netty-buffer:jar:4.1.42.Final:compile [INFO] | | +- io.netty:netty-transport:jar:4.1.42.Final:compile [INFO] | | +- io.netty:netty-handler:jar:4.1.42.Final:compile [INFO] | | +- io.netty:netty-handler-proxy:jar:4.1.42.Final:compile [INFO] | | | \- io.netty:netty-codec-socks:jar:4.1.42.Final:compile [INFO] | | +- io.netty:netty-codec-http2:jar:4.1.42.Final:compile [INFO] | | +- io.netty:netty-resolver:jar:4.1.42.Final:compile [INFO] | | \- io.netty:netty-resolver-dns:jar:4.1.42.Final:compile [INFO] | | \- io.netty:netty-codec-dns:jar:4.1.42.Final:compile [INFO] | \- io.quarkus.http:quarkus-http-http-core:jar:3.0.1.Final:compile [INFO] +- io.quarkus.http:quarkus-http-core:jar:3.0.1.Final:compile [INFO] | \- io.netty:netty-codec-http:jar:4.1.42.Final:compile [INFO] | \- io.netty:netty-codec:jar:4.1.42.Final:compile [INFO] \- org.eclipse.microprofile.context-propagation:microprofile-context-propagation-api:jar:1.0.1:com
アプリケーションの起動時には、ExtensionとしてServletが認識されています。
2020-01-25 19:18:56,652 INFO [io.quarkus] (main) Installed features: [cdi, resteasy, resteasy-jackson, servlet]
起動時に、XNIOのログも出力されず、スレッドダンプを取ったりするとNettyが現れるので、完全にNettyベースになったんですねぇ。
"vert.x-acceptor-thread-0" #31 prio=5 os_prio=0 tid=0x00007f46780a2800 nid=0x4722 runnable [0x00007f46a2dee000] java.lang.Thread.State: RUNNABLE at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method) at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269) at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93) at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86) - locked <0x00000006c6c26e60> (a io.netty.channel.nio.SelectedSelectionKeySet) - locked <0x00000006c6c27f60> (a java.util.Collections$UnmodifiableSet) - locked <0x00000006c6c27e88> (a sun.nio.ch.EPollSelectorImpl) at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97) at io.netty.channel.nio.SelectedSelectionKeySetSelector.select(SelectedSelectionKeySetSelector.java:62) at io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:824) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:457) at io.netty.util.concurrent.SingleThreadEventExecutor$6.run(SingleThreadEventExecutor.java:1044) at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.lang.Thread.run(Thread.java:748) "vert.x-eventloop-thread-15" #30 prio=5 os_prio=0 tid=0x00007f4711177800 nid=0x4721 runnable [0x00007f46a30ef000] java.lang.Thread.State: RUNNABLE at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method) at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269) at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93) at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86) - locked <0x00000006c6c06978> (a io.netty.channel.nio.SelectedSelectionKeySet) - locked <0x00000006c6c07a98> (a java.util.Collections$UnmodifiableSet) - locked <0x00000006c6c079a0> (a sun.nio.ch.EPollSelectorImpl) at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97) at io.netty.channel.nio.SelectedSelectionKeySetSelector.select(SelectedSelectionKeySetSelector.java:62) at io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:824) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:457) at io.netty.util.concurrent.SingleThreadEventExecutor$6.run(SingleThreadEventExecutor.java:1044) at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.lang.Thread.run(Thread.java:748) 〜省略〜 "vert.x-eventloop-thread-0" #15 prio=5 os_prio=0 tid=0x00007f471115e000 nid=0x4712 runnable [0x00007f46a3ffe000] java.lang.Thread.State: RUNNABLE at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method) at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269) at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93) at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86) - locked <0x00000006c6ce4040> (a io.netty.channel.nio.SelectedSelectionKeySet) - locked <0x00000006c6ce5150> (a java.util.Collections$UnmodifiableSet) - locked <0x00000006c6ce5068> (a sun.nio.ch.EPollSelectorImpl) at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97) at io.netty.channel.nio.SelectedSelectionKeySetSelector.select(SelectedSelectionKeySetSelector.java:62) at io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:824) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:457) at io.netty.util.concurrent.SingleThreadEventExecutor$6.run(SingleThreadEventExecutor.java:1044) at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.lang.Thread.run(Thread.java:748) "vertx-blocked-thread-checker" #13 daemon prio=5 os_prio=0 tid=0x00007f4710e52000 nid=0x4711 in Object.wait() [0x00007f46ac3db000] java.lang.Thread.State: TIMED_WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x00000006c6ce6148> (a java.util.TaskQueue) at java.util.TimerThread.mainLoop(Timer.java:552) - locked <0x00000006c6ce6148> (a java.util.TaskQueue) at java.util.TimerThread.run(Timer.java:505) 〜省略〜
先ほど作成したJAX-RSリソースクラスを使って、スタックトレースを出力してみます。
2020-01-25 19:18:58,459 INFO [org.lit.qua.res.HttpRequestResource] (executor-thread-1) Thread[executor-thread-1 / org.jboss.threads.JBossThread] java.lang.Exception: Stack trace at java.lang.Thread.dumpStack(Thread.java:1336) at org.littlewings.quarkus.resteasy.HttpRequestResource.printThreadDump(HttpRequestResource.java:38) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:151) at org.jboss.resteasy.core.MethodInjectorImpl.lambda$invoke$3(MethodInjectorImpl.java:122) at java.util.concurrent.CompletableFuture.uniApply(CompletableFuture.java:616) at java.util.concurrent.CompletableFuture.uniApplyStage(CompletableFuture.java:628) at java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:1996) at java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:110) at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:122) at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:594) at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:468) at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:421) at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:363) at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:423) at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:391) at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invoke$1(ResourceMethodInvoker.java:365) at java.util.concurrent.CompletableFuture.uniComposeStage(CompletableFuture.java:995) at java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:2137) at java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:110) at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:365) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:477) at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:252) at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:153) at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:363) at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:156) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:238) at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:249) at io.quarkus.resteasy.runtime.ResteasyFilter$ResteasyResponseWrapper.sendError(ResteasyFilter.java:65) at io.undertow.servlet.handlers.DefaultServlet.doGet(DefaultServlet.java:172) at javax.servlet.http.HttpServlet.service(HttpServlet.java:503) at javax.servlet.http.HttpServlet.service(HttpServlet.java:590) at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74) at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129) at io.quarkus.resteasy.runtime.ResteasyFilter.doFilter(ResteasyFilter.java:28) at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61) at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84) at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:63) at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68) at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:133) at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46) at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:65) at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60) at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77) at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50) at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:270) at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:59) at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:116) at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:113) at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48) at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43) at io.quarkus.undertow.runtime.UndertowDeploymentRecorder$9$1$1.call(UndertowDeploymentRecorder.java:482) at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:250) at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:59) at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:82) at io.undertow.server.Connectors.executeRootHandler(Connectors.java:290) at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:669) at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35) at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2011) at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1535) at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1395) at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29) at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29) at java.lang.Thread.run(Thread.java:748) at org.jboss.threads.JBossThread.run(JBossThread.java:479)
ここでは、がっつりとUndertowのAPIが登場します。
@GET @Path("print-servlet-request") @Produces(MediaType.APPLICATION_JSON) public Map<String, Object> printServletRequest(@Context HttpServletRequest request) { Map<String, Object> response = new LinkedHashMap<>(); response.put("method", request.getMethod()); response.put("request-url", request.getRequestURL()); response.put("request-uri", request.getRequestURI()); response.put("query", request.getQueryString()); return response; }
確認。
$ curl -s localhost:8080/http-request/print-servlet-request?param=hoge | jq { "method": "GET", "request-url": "http://localhost:8080/http-request/print-servlet-request", "request-uri": "/http-request/print-servlet-request", "query": "param=hoge" }
メソッド追加後のコードは、こちら。
src/main/java/org/littlewings/quarkus/resteasy/HttpRequestResource.java
package org.littlewings.quarkus.resteasy; import java.util.LinkedHashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import org.jboss.logging.Logger; import org.jboss.resteasy.spi.HttpRequest; @Path("http-request") public class HttpRequestResource { Logger logger = Logger.getLogger(HttpRequestResource.class); @GET @Path("print-request") @Produces(MediaType.APPLICATION_JSON) public Map<String, Object> printRequest(@Context HttpRequest request) { Map<String, Object> response = new LinkedHashMap<>(); response.put("method", request.getHttpMethod()); response.put("request-uri", request.getUri().getRequestUri().toString()); response.put("path", request.getUri().getPath()); response.put("query", request.getUri().getRequestUri().getQuery()); return response; } @GET @Path("thread-dump") @Produces(MediaType.TEXT_PLAIN) public String printThreadDump() { logger.infof("Thread[%s / %s]", Thread.currentThread().getName(), Thread.currentThread().getClass().getName()); Thread.dumpStack(); return "print Thread Dump"; } @GET @Path("print-servlet-request") @Produces(MediaType.APPLICATION_JSON) public Map<String, Object> printServletRequest(@Context HttpServletRequest request) { Map<String, Object> response = new LinkedHashMap<>(); response.put("method", request.getMethod()); response.put("request-url", request.getRequestURL()); response.put("request-uri", request.getRequestURI()); response.put("query", request.getQueryString()); return response; } }
ところでですね、依存関係にUndertowの名前がほとんど登場しなかったのに、スレッドダンプを見たらいきなり出てきたのがちょっと
気になります。
どうやら、こちらが実体のようですね。
GitHub - quarkusio/quarkus-http
A Vert.x based Servlet implementation.
らしいです。
こちらに置かれているコードのパッケージは、「io.undertow」となっていますし。
とりあえず、見たかったものはざっくりと見れたので、ここまで。