运行时与 JVM 优化

使用 jlink 为模块化 Vert.x 应用裁剪定制极简运行时

本文档将向你展示如何利用 Java 的 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 Plugin 将负责调度并执行底层的 jlink 命令行工具
2 为生成的自定义运行时归档包配置必须的分类器(Classifier)
3 server 是通过 jlink 自动生成的专属启动脚本名称(可选)
4 添加 jdk.jdwp.agent 调试模块,以便在需要时接入远程调试器

应用程序实现

模块描述符

首先定义 Java 模块描述符 src/main/java/module-info.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;
}

服务端实现

服务器业务逻辑仅需单个类 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);
  }
}

打包定制运行时

在终端执行打包命令:

./mvnw clean package

jlink 插件将分析当前模块依赖,仅提取真正用到的 JDK 核心模块,在 target/ 目录下生成自包含的专属 JRE 运行时。

运行裁剪后的自包含应用:

./target/maven-jlink/default/bin/server

访问 http://localhost:8080 即可验证服务正常响应!相比臃肿的数百兆完整 JDK,裁剪后的运行时体积仅有数十兆,非常适合轻量化部署与边缘计算场景。

总结

本文档展示了:

  • 基于 JPMS 模块化规范配置 Vert.x 应用;

  • 利用 maven-jlink-plugin 自动化裁剪无用的 JDK 模块;

  • 运行与验证独立的自包含极简 JRE 运行时。