构建 Vert.x 本机镜像

本操作指南展示了使用 GraalVM 构建 Vert.x 本机镜像所需的所有当前步骤和变通方法。

您将构建什么

  • 您将编写一个多 Verticle 应用程序(客户端 + 服务器)。

  • 代码将涵盖安全性(SSL)。

  • 借助 GraalVM,代码将被编译为本机代码。

您需要什么

  • 文本编辑器或 IDE

  • GraalVM (22.3.0)

  • Maven

什么是本机镜像,为什么 Vert.x 是一个很好的选择?

本机镜像是将 Java 应用程序优化转换为特定于操作系统/CPU 的本机代码。这个新应用程序将具有与传统 JVM 应用程序不同的特性,其中最显著的特点是

  • 更快的启动时间

  • (通常)更小的堆大小

因此,本机镜像非常适合 CLI无服务器 应用程序,但没有什么能阻止其也用于服务器应用程序。

本机镜像编译有几个限制(设计使然),其中大部分不适用于 Vert.x 核心代码。这使得 Vert.x 成为编写本机镜像的绝佳选择。然而,有一些已知的限制,可以很容易地通过变通方法来构建本机镜像。

本操作指南将涵盖这些限制,并解释如何使一个简单的 Vert.x 应用程序成为本机应用程序。

创建项目

首先创建一个遵循以下结构的新项目

├── pom.xml
└── src
    └── main
        └── java
            └── vertx
                └── APIClientVerticle.java
                └── HTTPVerticle.java
                └── HTTPSVerticle.java

之后,我们来回顾一下项目的重要部分。以下是您应该使用的 pom.xml 文件的内容

这是一个最小的 Hello World 项目。您可以阅读代码来确认这一点

package vertx;

import io.vertx.core.AbstractVerticle;

public class HTTPVerticle extends AbstractVerticle {

  @Override
  public void start() {
    vertx.createHttpServer().requestHandler(req -> {
      req.response()
        .putHeader("content-type", "text/plain")
        .end("Hello from Vert.x!");
    }).listen(8080, listen -> {
      if (listen.succeeded()) {
        System.out.println("Server listening on https://:8080/");
      } else {
        listen.cause().printStackTrace();
        System.exit(1);
      }
    });
  }
}

到目前为止,没有什么新东西。它是一个普通的 Vert.x Java 项目。

同样适用于其余源代码(稍后将介绍)。

添加 GraalVM Native Image Maven 插件

为了构建本机镜像,我们应该添加 native-image-maven-plugin

  1. 我们包含的插件应与已安装的 GraalVM 版本匹配。

  2. 指定镜像的最终名称(可执行文件的名称)

  3. 主启动类

  4. 传递给编译器的参数(在这种情况下,我们希望在出现问题时获得一些调试信息)。

构建镜像

构建镜像现在就像

mvn package

然而,由于声明的主类中没有 public static void main 方法,这将失败。我们可以通过将其添加到 HTTPVerticle 来解决此问题

  public static void main(String[] args) {
    Vertx.vertx().deployVerticle(new HTTPVerticle());
  }

或者配置 GraalVM 的反射配置,使其不排除我们的 Verticle

[
  {
    "name": "io.vertx.core.impl.launcher.commands.RunCommand",
    "allDeclaredConstructors": true,
    "allDeclaredMethods": true
  },
  {
    "name": "io.vertx.core.impl.launcher.commands.VertxIsolatedDeployer",
    "allDeclaredConstructors": true,
    "allDeclaredMethods": true
  },
  {
    "name": "java.lang.Long",
    "allDeclaredConstructors": true
  },
  {
    "name": "java.lang.Integer",
    "allDeclaredConstructors": true
  },

  {
    "name": "vertx.HTTPVerticle",
    "allDeclaredConstructors": true,
    "allDeclaredMethods": true
  },
  {
    "name": "vertx.HTTPSVerticle",
    "allDeclaredConstructors": true,
    "allDeclaredMethods": true
  },
  {
    "name": "vertx.APIClientVerticle",
    "allDeclaredConstructors": true,
    "allDeclaredMethods": true
  }
]

SSL

添加对 SSL 的支持并不困难,但需要一些更新。原因是安全库会显著增加最终二进制文件的大小,因此所有安全功能都通过标志禁用。还有其他注意事项,例如允许使用 Java 密钥库, 必须是 PKCS12 格式,这是 Java9 以来的新默认格式,但在 Java8(GraalVM 基于此版本)中不是。

您现在将向您的项目添加一个 HTTPS Verticle 服务器,在 vertx 包中现有类旁边创建 HTTPSVerticle

package vertx;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.http.HttpServerOptions;
import io.vertx.core.net.JksOptions;

public class HTTPSVerticle extends AbstractVerticle {

  @Override
  public void start() {
    vertx.createHttpServer(
      new HttpServerOptions()
        .setSsl(true)             // (1)
        .setKeyStoreOptions(
          new JksOptions()
            .setPath("certificates.keystore")   // (2)
            .setPassword("localhost")           // (3)
        )
    ).requestHandler(req -> {
      req.response()
        .putHeader("content-type", "text/plain")
        .end("Hello from Vert.x!");
    }).listen(8443, listen -> {
      if (listen.succeeded()) {
        System.out.println("Server listening on https://:8443/");
      } else {
        listen.cause().printStackTrace();
        System.exit(1);
      }
    });
  }
}
  1. 为此服务器启用 HTTPS。

  2. 指定从何处加载证书。

  3. 密钥库密码是什么(您不应该这样做,您应该从配置中获取密码,但为了简单起见,这里是硬编码的)。

您需要一个证书,因此这是所需的步骤

# Generate the self signed test certificate
$ keytool
  -genkey \
  -alias vertx \
  -keypass localhost \
  -keystore certificates.keystore \
  -storepass localhost \
  -keyalg RSA

# Convert to PCKS12
$ keytool \
  -importkeystore \
  -srckeystore certificates.keystore \
  -destkeystore certificates.keystore \
  -deststoretype pkcs12

如果您构建镜像,它将编译成功,但在运行时无法工作。还需要一件事

  1. 启用要添加到本机镜像的安全功能

要启用安全功能,必须将 graal plugin 配置为

<configuration>
  <imageName>${project.name}</imageName>
  <mainClass>${vertx.verticle}</mainClass>
  <buildArgs>--enable-all-security-services</buildArgs>
</configuration>

本机客户端

既然我们已经涵盖了基本的 SSL 安全性,我们就可以接触客户端了。在这个例子中,我们将使用一个简单的 HTTPS API。

package vertx;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.buffer.Buffer;
import io.vertx.ext.web.client.HttpResponse;
import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.client.WebClientOptions;

public class APIClientVerticle extends AbstractVerticle {

  @Override
  public void start() {
    WebClient client = WebClient.create(vertx, new WebClientOptions().setSsl(true).setTrustAll(true));

    client
      .get(443, "icanhazdadjoke.com", "/")
      .putHeader("Accept", "text/plain")
      .send(ar -> {
        if (ar.succeeded()) {
          HttpResponse<Buffer> response = ar.result();
          System.out.println("Got HTTP response with status " + response.statusCode() + " with data "
              + response.body().toString("ISO-8859-1"));
        } else {
          ar.cause().printStackTrace();
        }

        // Submit our API request and then exit (to make testing easier)
        getVertx().close();
    });
  }
}

这个客户端将发出一个 HTTPS 请求,并将输出打印到控制台。

构建

此时,您应该有一个基本的应用程序,并且您的 pom.xml 应该看起来像

<?xml version="1.0" encoding="UTF-8" ?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

  <modelVersion>4.0.0</modelVersion>

  <groupId>com.example</groupId>
  <artifactId>myapp</artifactId>
  <version>0.0.1-SNAPSHOT</version>

  <name>hello_native</name>

  <properties>
    <vertx.version>4.3.5</vertx.version>

    <graal.plugin.version>0.9.8</graal.plugin.version>
    <vertx.plugin.version>1.0.22</vertx.plugin.version>
    <failsafe.plugin.version>2.22.2</failsafe.plugin.version>
    <junit5.webclient.version>0.3.0</junit5.webclient.version>

    <vertx.verticle>vertx.APIClientVerticle</vertx.verticle>

    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.target>1.8</maven.compiler.target>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.testSource>1.8</maven.compiler.testSource>
    <maven.compiler.testTarget>1.8</maven.compiler.testTarget>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>io.vertx</groupId>
        <artifactId>vertx-stack-depchain</artifactId>
        <version>${vertx.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>io.vertx</groupId>
      <artifactId>vertx-core</artifactId>
    </dependency>
    <dependency>
      <groupId>io.vertx</groupId>
      <artifactId>vertx-web-client</artifactId>
    </dependency>
    <dependency>
      <groupId>io.vertx</groupId>
      <artifactId>vertx-junit5</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>io.reactiverse</groupId>
      <artifactId>reactiverse-junit5-web-client</artifactId>
      <version>${junit5.webclient.version}</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>io.reactiverse</groupId>
        <artifactId>vertx-maven-plugin</artifactId>
        <version>${vertx.plugin.version}</version>
        <executions>
          <execution>
            <id>vmp</id>
            <goals>
              <goal>initialize</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <redeploy>true</redeploy>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.graalvm.buildtools</groupId>
        <artifactId>native-maven-plugin</artifactId>
        <version>${graal.plugin.version}</version>
        <executions>
          <execution>
            <goals>
              <goal>build</goal>
            </goals>
            <phase>package</phase>
          </execution>
        </executions>
        <configuration>
          <imageName>${project.name}</imageName>
          <mainClass>io.vertx.core.Launcher</mainClass>
          <buildArgs>-H:+PrintClassInitialization -H:+ReportExceptionStackTraces</buildArgs>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-failsafe-plugin</artifactId>
        <version>${failsafe.plugin.version}</version>
        <executions>
          <execution>
            <goals>
              <goal>integration-test</goal>
              <goal>verify</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

运行 mvn clean package 将导致构建失败。目前,由于 vertx-core 仍然依赖于比 4.1.53 更旧的 netty 版本,我们需要手动导入上游添加的配置。这意味着我们需要添加一个新文件

├── pom.xml
└── src
    └── main
        └── resources
            └── META-INF/native-image/com.example/myapp
                └── native-image.properties

这个文件是需要传递给编译器的配置。目前文件相当大,但一旦 Vert.x 核心使用最新的 Netty,其中许多条目就可以删除,只列出 Vert.x 特定的条目。

Args =\
--enable-http \
--enable-https \
--allow-incomplete-classpath \
-H:EnableURLProtocols=http,https \
--report-unsupported-elements-at-runtime \
-H:ReflectionConfigurationResources=${.}/reflect-config.json \
-H:JNIConfigurationResources=${.}/jni-config.json \
-H:ResourceConfigurationResources=${.}/resource-config.json \
--initialize-at-run-time=\
io.netty.handler.codec.compression.ZstdOptions

运行编译将是

$ mvn package
[INFO] Scanning for projects...
[INFO]
[INFO] -------------------------< com.example:myapp >--------------------------
[INFO] Building hello_native 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ myapp ---
[INFO] Deleting /home/paulo/Projects/vertx-howtos/graal-native-image-howto/steps/step-2/target
[INFO]
[INFO] --- vertx-maven-plugin:1.0.22:initialize (vmp) @ myapp ---
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ myapp ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 4 resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ myapp ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 3 source files to /home/paulo/Projects/vertx-howtos/graal-native-image-howto/steps/step-2/target/classes
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ myapp ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /home/paulo/Projects/vertx-howtos/graal-native-image-howto/steps/step-2/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ myapp ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /home/paulo/Projects/vertx-howtos/graal-native-image-howto/steps/step-2/target/test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ myapp ---
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ myapp ---
[INFO] Building jar: /home/paulo/Projects/vertx-howtos/graal-native-image-howto/steps/step-2/target/myapp-0.0.1-SNAPSHOT.jar
[INFO]
[INFO] --- native-maven-plugin:0.9.8:build (default) @ myapp ---
[INFO] ImageClasspath Entry: io.vertx:vertx-core:jar:4.3.5:compile (file:///home/paulo/.m2/repository/io/vertx/vertx-core/4.3.5/vertx-core-4.3.5.jar)
[INFO] ImageClasspath Entry: io.netty:netty-common:jar:4.1.85.Final:compile (file:///home/paulo/.m2/repository/io/netty/netty-common/4.1.85.Final/netty-common-4.1.85.Final.jar)
[INFO] ImageClasspath Entry: io.netty:netty-buffer:jar:4.1.85.Final:compile (file:///home/paulo/.m2/repository/io/netty/netty-buffer/4.1.85.Final/netty-buffer-4.1.85.Final.jar)
[INFO] ImageClasspath Entry: io.netty:netty-transport:jar:4.1.85.Final:compile (file:///home/paulo/.m2/repository/io/netty/netty-transport/4.1.85.Final/netty-transport-4.1.85.Final.jar)
[INFO] ImageClasspath Entry: io.netty:netty-handler:jar:4.1.85.Final:compile (file:///home/paulo/.m2/repository/io/netty/netty-handler/4.1.85.Final/netty-handler-4.1.85.Final.jar)
[INFO] ImageClasspath Entry: io.netty:netty-transport-native-unix-common:jar:4.1.85.Final:compile (file:///home/paulo/.m2/repository/io/netty/netty-transport-native-unix-common/4.1.85.Final/netty-transport-native-unix-common-4.1.85.Final.jar)
[INFO] ImageClasspath Entry: io.netty:netty-codec:jar:4.1.85.Final:compile (file:///home/paulo/.m2/repository/io/netty/netty-codec/4.1.85.Final/netty-codec-4.1.85.Final.jar)
[INFO] ImageClasspath Entry: io.netty:netty-handler-proxy:jar:4.1.85.Final:compile (file:///home/paulo/.m2/repository/io/netty/netty-handler-proxy/4.1.85.Final/netty-handler-proxy-4.1.85.Final.jar)
[INFO] ImageClasspath Entry: io.netty:netty-codec-socks:jar:4.1.85.Final:compile (file:///home/paulo/.m2/repository/io/netty/netty-codec-socks/4.1.85.Final/netty-codec-socks-4.1.85.Final.jar)
[INFO] ImageClasspath Entry: io.netty:netty-codec-http:jar:4.1.85.Final:compile (file:///home/paulo/.m2/repository/io/netty/netty-codec-http/4.1.85.Final/netty-codec-http-4.1.85.Final.jar)
[INFO] ImageClasspath Entry: io.netty:netty-codec-http2:jar:4.1.85.Final:compile (file:///home/paulo/.m2/repository/io/netty/netty-codec-http2/4.1.85.Final/netty-codec-http2-4.1.85.Final.jar)
[INFO] ImageClasspath Entry: io.netty:netty-resolver:jar:4.1.85.Final:compile (file:///home/paulo/.m2/repository/io/netty/netty-resolver/4.1.85.Final/netty-resolver-4.1.85.Final.jar)
[INFO] ImageClasspath Entry: io.netty:netty-resolver-dns:jar:4.1.85.Final:compile (file:///home/paulo/.m2/repository/io/netty/netty-resolver-dns/4.1.85.Final/netty-resolver-dns-4.1.85.Final.jar)
[INFO] ImageClasspath Entry: io.netty:netty-codec-dns:jar:4.1.85.Final:compile (file:///home/paulo/.m2/repository/io/netty/netty-codec-dns/4.1.85.Final/netty-codec-dns-4.1.85.Final.jar)
[INFO] ImageClasspath Entry: com.fasterxml.jackson.core:jackson-core:jar:2.14.0:compile (file:///home/paulo/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.14.0/jackson-core-2.14.0.jar)
[INFO] ImageClasspath Entry: io.vertx:vertx-web-client:jar:4.3.5:compile (file:///home/paulo/.m2/repository/io/vertx/vertx-web-client/4.3.5/vertx-web-client-4.3.5.jar)
[INFO] ImageClasspath Entry: io.vertx:vertx-uri-template:jar:4.3.5:compile (file:///home/paulo/.m2/repository/io/vertx/vertx-uri-template/4.3.5/vertx-uri-template-4.3.5.jar)
[INFO] ImageClasspath Entry: io.vertx:vertx-web-common:jar:4.3.5:compile (file:///home/paulo/.m2/repository/io/vertx/vertx-web-common/4.3.5/vertx-web-common-4.3.5.jar)
[INFO] ImageClasspath Entry: io.vertx:vertx-auth-common:jar:4.3.5:compile (file:///home/paulo/.m2/repository/io/vertx/vertx-auth-common/4.3.5/vertx-auth-common-4.3.5.jar)
[INFO] ImageClasspath Entry: com.example:myapp:jar:0.0.1-SNAPSHOT (file:///home/paulo/Projects/vertx-howtos/graal-native-image-howto/steps/step-2/target/myapp-0.0.1-SNAPSHOT.jar)
[INFO] Executing: /home/paulo/.jdks/graalvm-ce-java11-22.3.0/bin/native-image -cp /home/paulo/.m2/repository/io/vertx/vertx-core/4.3.5/vertx-core-4.3.5.jar:/home/paulo/.m2/repository/io/netty/netty-common/4.1.85.Final/netty-common-4.1.85.Final.jar:/home/paulo/.m2/repository/io/netty/netty-buffer/4.1.85.Final/netty-buffer-4.1.85.Final.jar:/home/paulo/.m2/repository/io/netty/netty-transport/4.1.85.Final/netty-transport-4.1.85.Final.jar:/home/paulo/.m2/repository/io/netty/netty-handler/4.1.85.Final/netty-handler-4.1.85.Final.jar:/home/paulo/.m2/repository/io/netty/netty-transport-native-unix-common/4.1.85.Final/netty-transport-native-unix-common-4.1.85.Final.jar:/home/paulo/.m2/repository/io/netty/netty-codec/4.1.85.Final/netty-codec-4.1.85.Final.jar:/home/paulo/.m2/repository/io/netty/netty-handler-proxy/4.1.85.Final/netty-handler-proxy-4.1.85.Final.jar:/home/paulo/.m2/repository/io/netty/netty-codec-socks/4.1.85.Final/netty-codec-socks-4.1.85.Final.jar:/home/paulo/.m2/repository/io/netty/netty-codec-http/4.1.85.Final/netty-codec-http-4.1.85.Final.jar:/home/paulo/.m2/repository/io/netty/netty-codec-http2/4.1.85.Final/netty-codec-http2-4.1.85.Final.jar:/home/paulo/.m2/repository/io/netty/netty-resolver/4.1.85.Final/netty-resolver-4.1.85.Final.jar:/home/paulo/.m2/repository/io/netty/netty-resolver-dns/4.1.85.Final/netty-resolver-dns-4.1.85.Final.jar:/home/paulo/.m2/repository/io/netty/netty-codec-dns/4.1.85.Final/netty-codec-dns-4.1.85.Final.jar:/home/paulo/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.14.0/jackson-core-2.14.0.jar:/home/paulo/.m2/repository/io/vertx/vertx-web-client/4.3.5/vertx-web-client-4.3.5.jar:/home/paulo/.m2/repository/io/vertx/vertx-uri-template/4.3.5/vertx-uri-template-4.3.5.jar:/home/paulo/.m2/repository/io/vertx/vertx-web-common/4.3.5/vertx-web-common-4.3.5.jar:/home/paulo/.m2/repository/io/vertx/vertx-auth-common/4.3.5/vertx-auth-common-4.3.5.jar:/home/paulo/Projects/vertx-howtos/graal-native-image-howto/steps/step-2/target/myapp-0.0.1-SNAPSHOT.jar -H:+PrintClassInitialization -H:+ReportExceptionStackTraces -H:Class=io.vertx.core.Launcher -H:Name=hello_native
Warning: Using a deprecated option --allow-incomplete-classpath from 'META-INF/native-image/com.example/myapp/native-image.properties' in 'file:///home/paulo/Projects/vertx-howtos/graal-native-image-howto/steps/step-2/target/myapp-0.0.1-SNAPSHOT.jar'. Allowing an incomplete classpath is now the default. Use --link-at-build-time to report linking errors at image build time for a class or package.
========================================================================================================================
GraalVM Native Image: Generating 'hello_native' (executable)...
========================================================================================================================
Warning: Could not register io.netty.handler.codec.compression.Lz4FrameDecoder: queryAllPublicMethods for reflection. Reason: java.lang.NoClassDefFoundError: net/jpountz/lz4/LZ4Exception.
Warning: Could not register io.netty.handler.codec.compression.Lz4FrameEncoder: queryAllPublicMethods for reflection. Reason: java.lang.NoClassDefFoundError: net/jpountz/lz4/LZ4Exception.
Warning: Could not register io.netty.handler.codec.marshalling.CompatibleMarshallingDecoder: queryAllPublicMethods for reflection. Reason: java.lang.NoClassDefFoundError: org/jboss/marshalling/ByteInput.
Warning: Could not register io.netty.handler.codec.marshalling.CompatibleMarshallingEncoder: queryAllPublicMethods for reflection. Reason: java.lang.NoClassDefFoundError: org/jboss/marshalling/ByteOutput.
Warning: Could not register io.netty.handler.codec.marshalling.MarshallingDecoder: queryAllPublicMethods for reflection. Reason: java.lang.NoClassDefFoundError: org/jboss/marshalling/ByteInput.
Warning: Could not register io.netty.handler.codec.marshalling.MarshallingEncoder: queryAllPublicMethods for reflection. Reason: java.lang.NoClassDefFoundError: org/jboss/marshalling/ByteOutput.
Warning: Could not register io.netty.handler.codec.protobuf.ProtobufDecoder: queryAllPublicMethods for reflection. Reason: java.lang.NoClassDefFoundError: com/google/protobuf/ExtensionRegistryLite.
Warning: Could not register io.netty.handler.codec.compression.Lz4FrameDecoder: queryAllPublicMethods for reflection. Reason: java.lang.NoClassDefFoundError: net/jpountz/lz4/LZ4Exception.
Warning: Could not register io.netty.handler.codec.compression.Lz4FrameEncoder: queryAllPublicMethods for reflection. Reason: java.lang.NoClassDefFoundError: net/jpountz/lz4/LZ4Exception.
Warning: Could not register io.netty.handler.codec.marshalling.CompatibleMarshallingDecoder: queryAllPublicMethods for reflection. Reason: java.lang.NoClassDefFoundError: org/jboss/marshalling/ByteInput.
Warning: Could not register io.netty.handler.codec.marshalling.CompatibleMarshallingEncoder: queryAllPublicMethods for reflection. Reason: java.lang.NoClassDefFoundError: org/jboss/marshalling/ByteOutput.
Warning: Could not register io.netty.handler.codec.marshalling.MarshallingDecoder: queryAllPublicMethods for reflection. Reason: java.lang.NoClassDefFoundError: org/jboss/marshalling/ByteInput.
Warning: Could not register io.netty.handler.codec.marshalling.MarshallingEncoder: queryAllPublicMethods for reflection. Reason: java.lang.NoClassDefFoundError: org/jboss/marshalling/ByteOutput.
Warning: Could not register io.netty.handler.codec.protobuf.ProtobufDecoder: queryAllPublicMethods for reflection. Reason: java.lang.NoClassDefFoundError: com/google/protobuf/ExtensionRegistryLite.
[1/7] Initializing...                                                                                    (2.9s @ 0.24GB)
 Version info: 'GraalVM 22.3.0 Java 11 CE'
 Java version info: '11.0.17+8-jvmci-22.3-b08'
 C compiler: gcc (linux, x86_64, 12.2.0)
 Garbage collector: Serial GC
# Printing class initialization configuration to: /home/paulo/Projects/vertx-howtos/graal-native-image-howto/steps/step-2/target/reports/class_initialization_configuration_20221129_125610.csv
[2/7] Performing analysis...  [*WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by io.netty.util.internal.ReflectionUtil (file:/home/paulo/.m2/repository/io/netty/netty-common/4.1.85.Final/netty-common-4.1.85.Final.jar) to constructor java.nio.DirectByteBuffer(long,int)
WARNING: Please consider reporting this to the maintainers of io.netty.util.internal.ReflectionUtil
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
Nov 29, 2022 12:56:21 PM io.netty.handler.ssl.BouncyCastleAlpnSslUtils <clinit>
SEVERE: Unable to initialize BouncyCastleAlpnSslUtils.
java.lang.ClassNotFoundException: org.bouncycastle.jsse.BCSSLEngine
	at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:476)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:589)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
	at java.base/java.lang.Class.forName0(Native Method)
	at java.base/java.lang.Class.forName(Class.java:315)
	at io.netty.handler.ssl.BouncyCastleAlpnSslUtils.<clinit>(BouncyCastleAlpnSslUtils.java:63)
	at java.base/jdk.internal.misc.Unsafe.ensureClassInitialized0(Native Method)
	at java.base/jdk.internal.misc.Unsafe.ensureClassInitialized(Unsafe.java:1042)
	at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.classinitialization.ClassInitializationSupport.ensureClassInitialized(ClassInitializationSupport.java:172)
	at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.classinitialization.ProvenSafeClassInitializationSupport.computeInitKindAndMaybeInitializeClass(ProvenSafeClassInitializationSupport.java:344)
	at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.classinitialization.ProvenSafeClassInitializationSupport.computeInitKindAndMaybeInitializeClass(ProvenSafeClassInitializationSupport.java:75)
	at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.classinitialization.ClassInitializationSupport.shouldInitializeAtRuntime(ClassInitializationSupport.java:148)
	at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.SVMHost.isInitialized(SVMHost.java:297)
	at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.meta.AnalysisType.isInitialized(AnalysisType.java:882)
	at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.maybeEagerlyInitialize(BytecodeParser.java:4304)
	at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.genInvokeStatic(BytecodeParser.java:1658)
	at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.genInvokeStatic(BytecodeParser.java:1651)
	at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.processBytecode(BytecodeParser.java:5288)
	at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.iterateBytecodesForBlock(BytecodeParser.java:3385)
	at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.handleBytecodeBlock(BytecodeParser.java:3345)
	at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.processBlock(BytecodeParser.java:3190)
	at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.build(BytecodeParser.java:1138)
	at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.buildRootMethod(BytecodeParser.java:1030)
	at jdk.internal.vm.compiler/org.graalvm.compiler.java.GraphBuilderPhase$Instance.run(GraphBuilderPhase.java:97)
	at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.phases.SharedGraphBuilderPhase.run(SharedGraphBuilderPhase.java:84)
	at jdk.internal.vm.compiler/org.graalvm.compiler.phases.Phase.run(Phase.java:49)
	at jdk.internal.vm.compiler/org.graalvm.compiler.phases.BasePhase.apply(BasePhase.java:446)
	at jdk.internal.vm.compiler/org.graalvm.compiler.phases.Phase.apply(Phase.java:42)
	at jdk.internal.vm.compiler/org.graalvm.compiler.phases.Phase.apply(Phase.java:38)
	at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.flow.AnalysisParsedGraph.parseBytecode(AnalysisParsedGraph.java:135)
	at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.meta.AnalysisMethod.ensureGraphParsed(AnalysisMethod.java:685)
	at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder.parse(MethodTypeFlowBuilder.java:171)
	at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder.apply(MethodTypeFlowBuilder.java:349)
	at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.flow.MethodTypeFlow.createFlowsGraph(MethodTypeFlow.java:93)
	at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.flow.MethodTypeFlow.ensureFlowsGraphCreated(MethodTypeFlow.java:83)
	at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.flow.MethodTypeFlow.getOrCreateMethodFlowsGraph(MethodTypeFlow.java:65)
	at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.typestate.DefaultVirtualInvokeTypeFlow.onObservedUpdate(DefaultVirtualInvokeTypeFlow.java:109)
	at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.flow.TypeFlow.lambda$addObserver$0(TypeFlow.java:455)
	at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.util.CompletionExecutor.executeCommand(CompletionExecutor.java:193)
	at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.util.CompletionExecutor.lambda$executeService$0(CompletionExecutor.java:177)
	at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1426)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183)

# Printing class initialization dependencies to: /home/paulo/Projects/vertx-howtos/graal-native-image-howto/steps/step-2/target/reports/class_initialization_dependencies_20221129_125640.dot
# Printing class initialization report to: /home/paulo/Projects/vertx-howtos/graal-native-image-howto/steps/step-2/target/reports/class_initialization_report_20221129_125640.csv
[2/7] Performing analysis...  [**********]                                                              (30.0s @ 4.34GB)
  10,678 (89.69%) of 11,905 classes reachable
  18,919 (64.59%) of 29,293 fields reachable
  55,090 (60.41%) of 91,201 methods reachable
     428 classes,     6 fields, and 1,602 methods registered for reflection
      69 classes,    88 fields, and    56 methods registered for JNI access
       5 native libraries: dl, pthread, rt, stdc++, z
[3/7] Building universe...                                                                               (7.1s @ 2.74GB)
[4/7] Parsing methods...      [**]                                                                       (4.1s @ 2.03GB)
[5/7] Inlining methods...     [***]                                                                      (2.0s @ 3.71GB)
[6/7] Compiling methods...    [*****]                                                                   (27.2s @ 3.15GB)
[7/7] Creating image...                                                                                  (3.0s @ 4.61GB)
  22.78MB (49.38%) for code area:    34,998 compilation units
  21.08MB (45.71%) for image heap:  260,328 objects and 14 resources
   2.26MB ( 4.91%) for other data
  46.12MB in total
------------------------------------------------------------------------------------------------------------------------
Top 10 packages in code area:                               Top 10 object types in image heap:
   2.44MB com.sun.tools.javac.comp                             5.00MB byte[] for code metadata
   1.56MB sun.security.ssl                                     2.60MB java.lang.Class
 948.92KB java.util                                            2.51MB java.lang.String
 849.89KB com.sun.tools.javac.code                             2.21MB byte[] for general heap data
 685.28KB com.sun.tools.javac.jvm                              1.87MB byte[] for java.lang.String
 675.29KB com.sun.crypto.provider                           1001.06KB com.oracle.svm.core.hub.DynamicHubCompanion
 473.62KB sun.security.x509                                  534.83KB byte[] for reflection metadata
 470.83KB java.lang                                          504.76KB java.lang.String[]
 426.55KB com.sun.tools.javac.parser                         459.23KB java.util.HashMap$Node
 418.89KB io.netty.buffer                                    384.30KB c.o.svm.core.hub.DynamicHub$ReflectionMetadata
  13.69MB for 312 more packages                                3.40MB for 2390 more object types
------------------------------------------------------------------------------------------------------------------------
                        3.4s (4.2% of total time) in 28 GCs | Peak RSS: 6.14GB | CPU load: 6.40
------------------------------------------------------------------------------------------------------------------------
Produced artifacts:
 /home/paulo/Projects/vertx-howtos/graal-native-image-howto/steps/step-2/target/hello_native (executable)
 /home/paulo/Projects/vertx-howtos/graal-native-image-howto/steps/step-2/target/hello_native.build_artifacts.txt (txt)
========================================================================================================================
Finished generating 'hello_native' in 1m 20s.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  01:21 min
[INFO] Finished at: 2022-11-29T12:57:27+01:00
[INFO] ------------------------------------------------------------------------

运行应用程序将像

$ ./target/hello_native run vertx.APIClientVerticle
Got HTTP response with status 200 with data Two peanuts were walking down the street. One was a salted.
^C

$ ./target/hello_native run vertx.HTTPServer
Dec 02, 2020 7:51:56 PM io.netty.channel.DefaultChannelId defaultProcessId
WARNING: Failed to find the current process ID from ''; using a random value: 1891971538
Dec 02, 2020 7:51:56 PM io.vertx.core.impl.launcher.commands.VertxIsolatedDeployer
INFO: Succeeded in deploying verticle
Server listening on https://:8080/
^C

$ ./target/hello_native run vertx.HTTPSServer
Dec 02, 2020 7:56:25 PM io.netty.channel.DefaultChannelId defaultProcessId
WARNING: Failed to find the current process ID from ''; using a random value: -1125265761
Dec 02, 2020 7:56:25 PM io.vertx.core.impl.launcher.commands.VertxIsolatedDeployer
INFO: Succeeded in deploying verticle
Server listening on https://:8443/
^C
注意
如果您有兴趣了解内存使用情况,只需执行:ps x -o pid,rss,command|grep hello_native,您将看到类似以下内容:59751 35484 ./target/hello_native run vertx.HTTPVerticle 大约 36MB

您现在已将所有 Verticle 放在同一个镜像中。请记住,您现在可以使用启动器执行所有操作,例如为 HTTP 服务器扩展 Verticle 的数量

$ ./target/hello_native run vertx.HTTPVerticle -instances 4
Server listening on https://:8080/
Server listening on https://:8080/
Server listening on https://:8080/
Server listening on https://:8080/
^C

至此,本机镜像操作指南结束。

本操作指南的完整源代码可在 此处 找到

总结

  • 我们编写了一个 HTTP 服务器 Verticle。

  • 我们添加了构建镜像所需的元数据。

  • 我们编写了一个 HTTPS 服务器 Verticle。

  • 我们添加了构建镜像所需的安全 DLL 和配置。

  • 我们编写了一个 HTTPS 客户端 Verticle。

  • 我们通过指定类的加载顺序处理了一个构建问题。

  • 我们配置了反射和资源,以便在一个镜像中拥有多个 Verticle。


最后发布:2025-02-05 00:57:02 +0000。