使用 jlink 组装模块化 Vert.x 应用程序的小型运行时镜像

本文档将向您展示如何使用 jlink 组装模块化 Vert.x 应用程序的小型运行时镜像。

您需要什么

  • 文本编辑器或 IDE

  • Java 11 或更高版本

创建项目

以下是您应该使用的 Maven pom.xml 文件的内容

Maven 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>io.vertx.howtos</groupId>
  <artifactId>jlink-howto</artifactId>
  <version>1.0-SNAPSHOT</version>

  <properties>
    <vertx.version>5.0.0.CR4</vertx.version>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </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-launcher-application</artifactId>
    </dependency>
    <dependency>
      <groupId>io.vertx</groupId>
      <artifactId>vertx-web</artifactId>
    </dependency>
  </dependencies>

  <build>
    <finalName>jlink-howto</finalName>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.13.0</version>
        <configuration>
          <release>11</release>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jlink-plugin</artifactId> <!--(1)-->
        <version>3.2.0</version>
        <executions>
          <execution>
            <id>jlink</id>
            <goals>
              <goal>jlink</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <classifier>dist</classifier> <!--(2)-->
          <launcher>server=io.vertx.howtos.jlink/io.vertx.howtos.jlink.CustomLauncher</launcher> <!--(3)-->
          <addModules>jdk.jdwp.agent</addModules> <!--(4)-->
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>
  1. Apache Maven JLink 插件 将负责调用 jlink 命令行工具。

  2. 作为 Maven artifact 附加的自定义运行时镜像归档的强制分类器。

  3. server 是通过 jlink 生成的启动脚本的名称。这是可选的。

  4. 添加 jdk.jdwp.agent 模块,以便在需要时我们可以附加远程调试器。

实现应用程序

服务器设置代码包含在一个类中:io.vertx.howtos.jlink.ServerVerticle

package io.vertx.howtos.jlink;

import io.vertx.core.AbstractVerticle;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.ext.web.Router;

import java.util.logging.Logger;

public class ServerVerticle extends AbstractVerticle {

  private static final Logger LOG = Logger.getLogger(ServerVerticle.class.getName());

  @Override
  public void start(Promise<Void> startPromise) {
    Router router = Router.router(vertx);

    router.get().respond(rc -> Future.succeededFuture("Hello World!"));

    vertx.createHttpServer()
      .requestHandler(router)
      .listen(8888)
      .onSuccess(http -> LOG.info("HTTP server started on port 8888"))
      .<Void>mapEmpty()
      .onComplete(startPromise);
  }
}

自定义应用程序启动器为主 verticle 的部署提供了工厂

package io.vertx.howtos.jlink;

import io.vertx.core.Verticle;
import io.vertx.launcher.application.VertxApplication;
import io.vertx.launcher.application.VertxApplicationHooks;

import java.util.function.Supplier;

public class CustomLauncher extends VertxApplication implements VertxApplicationHooks {

  public static void main(String[] args) {
    CustomLauncher vertxApplication = new CustomLauncher(args);
    vertxApplication.launch();
  }

  public CustomLauncher(String[] args) {
    super(args);
  }

  @Override
  public Supplier<Verticle> verticleSupplier() {
    return ServerVerticle::new;
  }
}

将 verticle 工厂放在 io.vertx.howtos.jlink.CustomLauncher 中简化了 Java 模块配置

module io.vertx.howtos.jlink {
  requires io.vertx.core;
  requires io.vertx.launcher.application;
  requires io.vertx.web;
  requires io.vertx.auth.common;
  requires java.logging;
}

实际上,由于 verticle 实例不会通过反射创建,我们不必将应用程序包导出到 io.vertx.core 模块,我们只需要声明几个必需的模块。

构建应用程序

在 Linux 或其他类 Unix 系统上,运行以下命令

./mvnw clean package

在 Microsoft Windows 上

mvnw.cmd clean package

请注意,所有必需的模块在 jlink 创建自定义运行时镜像之前都会被解析。

[INFO] --- jlink:3.2.0:jlink (jlink) @ jlink-howto ---
[INFO]  -> module: io.netty.handler ( /path/to/my/mavenrepo/io/netty/netty-handler/4.2.0.RC1/netty-handler-4.2.0.RC1.jar )
[INFO]  -> module: io.vertx.web ( /path/to/my/mavenrepo/io/vertx/vertx-web/5.0.0.CR4/vertx-web-5.0.0.CR4.jar )
[INFO]  -> module: io.vertx.core ( /path/to/my/mavenrepo/io/vertx/vertx-core/5.0.0.CR4/vertx-core-5.0.0.CR4.jar )
[INFO]  -> module: io.netty.handler.proxy ( /path/to/my/mavenrepo/io/netty/netty-handler-proxy/4.2.0.RC1/netty-handler-proxy-4.2.0.RC1.jar )
[INFO]  -> module: com.fasterxml.jackson.core ( /path/to/my/mavenrepo/com/fasterxml/jackson/core/jackson-core/2.16.1/jackson-core-2.16.1.jar )
[INFO]  -> module: io.netty.codec.unused ( /path/to/my/mavenrepo/io/netty/netty-codec/4.2.0.RC1/netty-codec-4.2.0.RC1.jar )
[INFO]  -> module: io.vertx.launcher.application ( /path/to/my/mavenrepo/io/vertx/vertx-launcher-application/5.0.0.CR4/vertx-launcher-application-5.0.0.CR4.jar )
[INFO]  -> module: io.vertx.auth.common ( /path/to/my/mavenrepo/io/vertx/vertx-auth-common/5.0.0.CR4/vertx-auth-common-5.0.0.CR4.jar )
[INFO]  -> module: info.picocli ( /path/to/my/mavenrepo/info/picocli/picocli/4.7.4/picocli-4.7.4.jar )
[INFO]  -> module: io.vertx.howtos.jlink ( /path/to/my/Projects/vertx-howtos/jlink-howto/target/classes )
[INFO]  -> module: io.netty.transport.unix.common ( /path/to/my/mavenrepo/io/netty/netty-transport-native-unix-common/4.2.0.RC1/netty-transport-native-unix-common-4.2.0.RC1.jar )
[INFO]  -> module: io.netty.codec.compression ( /path/to/my/mavenrepo/io/netty/netty-codec-compression/4.2.0.RC1/netty-codec-compression-4.2.0.RC1.jar )
[INFO]  -> module: io.vertx.web.common ( /path/to/my/mavenrepo/io/vertx/vertx-web-common/5.0.0.CR4/vertx-web-common-5.0.0.CR4.jar )
[INFO]  -> module: io.netty.buffer ( /path/to/my/mavenrepo/io/netty/netty-buffer/4.2.0.RC1/netty-buffer-4.2.0.RC1.jar )
[INFO]  -> module: io.netty.codec.http2 ( /path/to/my/mavenrepo/io/netty/netty-codec-http2/4.2.0.RC1/netty-codec-http2-4.2.0.RC1.jar )
[INFO]  -> module: io.vertx.core.logging ( /path/to/my/mavenrepo/io/vertx/vertx-core-logging/5.0.0.CR4/vertx-core-logging-5.0.0.CR4.jar )
[INFO]  -> module: io.netty.common ( /path/to/my/mavenrepo/io/netty/netty-common/4.2.0.RC1/netty-common-4.2.0.RC1.jar )
[INFO]  -> module: io.netty.resolver.dns ( /path/to/my/mavenrepo/io/netty/netty-resolver-dns/4.2.0.RC1/netty-resolver-dns-4.2.0.RC1.jar )
[INFO]  -> module: io.netty.codec.http ( /path/to/my/mavenrepo/io/netty/netty-codec-http/4.2.0.RC1/netty-codec-http-4.2.0.RC1.jar )
[INFO]  -> module: io.netty.codec.socks ( /path/to/my/mavenrepo/io/netty/netty-codec-socks/4.2.0.RC1/netty-codec-socks-4.2.0.RC1.jar )
[INFO]  -> module: io.netty.codec.dns ( /path/to/my/mavenrepo/io/netty/netty-codec-dns/4.2.0.RC1/netty-codec-dns-4.2.0.RC1.jar )
[INFO]  -> module: io.netty.transport ( /path/to/my/mavenrepo/io/netty/netty-transport/4.2.0.RC1/netty-transport-4.2.0.RC1.jar )
[INFO]  -> module: io.netty.codec ( /path/to/my/mavenrepo/io/netty/netty-codec-base/4.2.0.RC1/netty-codec-base-4.2.0.RC1.jar )
[INFO]  -> module: io.netty.resolver ( /path/to/my/mavenrepo/io/netty/netty-resolver/4.2.0.RC1/netty-resolver-4.2.0.RC1.jar )
[INFO]  -> module: io.vertx.eventbusbridge ( /path/to/my/mavenrepo/io/vertx/vertx-bridge-common/5.0.0.CR4/vertx-bridge-common-5.0.0.CR4.jar )
[INFO] Building zip: /path/to/my/vertx-howtos/jlink-howto/target/jlink-howto-dist.zip

运行应用程序

target/jlink-howto-dist.zip 归档文件解压到您磁盘上的某个位置。在 Linux 或其他类 Unix 系统上,您可以使用以下命令完成此操作

unzip -d target/jlink-howto target/jlink-howto-dist.zip

检查自定义运行时镜像文件夹的总大小。在 Linux 或其他类 Unix 系统上,您可以使用以下命令完成此操作

du -sh target/jlink-howto

在我的机器上,结果是 68 MB。相比之下,JDK 11 分发版的总大小是 312 MB。

现在是时候尝试一下应用程序了。在 Linux 或其他类 Unix 系统上,您可以使用以下命令完成此操作

target/jlink-howto/bin/java --module io.vertx.howtos.jlink/io.vertx.howtos.jlink.CustomLauncher

或者,您可以使用生成的 server 脚本

target/jlink-howto/bin/server

您应该会看到类似以下内容:

Feb 03, 2025 6:48:31 PM io.vertx.howtos.jlink.ServerVerticle lambda$start$1
INFO: HTTP server started on port 8888
Feb 03, 2025 6:48:31 PM io.vertx.launcher.application.VertxApplication
INFO: Succeeded in deploying verticle

现在,浏览到 https://:8888 并验证浏览器中是否显示了问候语。

注意

当使用启动器脚本时,无法将 VM 选项(堆大小、远程调试等)指定为参数。

您可以更改 server 脚本中的 JLINK_VM_OPTIONS 变量或使用 java 命令。

例如,在 Linux 或其他类 Unix 系统上进行远程调试

target/jlink-howto/bin/java \
  -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005 \
  --module io.vertx.howtos.jlink/io.vertx.howtos.jlink.CustomLauncher

总结

本文档涵盖了

  1. 创建模块化 Vert.x Web 应用程序,

  2. 使用 jlink 组装自定义运行时镜像。


最后发布:2025-04-06 01:49:21 +0000。