首页 > Java > java教程 > 正文

使用 jlink 为 Spring Boot 3.0 应用构建自定义运行时环境

聖光之護
发布: 2025-11-10 17:20:01
原创
639人浏览过

使用 jlink 为 Spring Boot 3.0 应用构建自定义运行时环境

本文旨在指导读者如何利用 java 19 的 `jlink` 工具为 spring boot 3.0 应用创建精简的自定义运行时环境。通过详细分析 `jdeps` 输出,识别并添加 spring boot 应用程序所需的 jdk 模块,解决了因模块缺失导致的 `noclassdeffounderror` 问题,从而实现更小、更高效的部署包。

引言:jlink 与 Spring Boot 应用优化

随着 Java 平台模块系统(JPMS)的引入,jlink 工具为开发者提供了构建自定义运行时镜像的能力,这对于部署云原生应用或需要极小运行时环境的场景尤为有益。通过 jlink,我们可以将应用程序及其所需的 JDK 模块打包成一个独立的、精简的运行时环境,从而减少部署包大小、提升启动速度。

本教程将以一个基于 Java 19 和 Spring Boot 3.0 的简单应用为例,演示如何从零开始,逐步分析依赖,并最终成功构建一个可运行的自定义运行时镜像。

1. Spring Boot 应用基础设置

首先,我们创建一个基本的 Spring Boot 3.0 应用。可以通过 start.spring.io 生成一个 Maven 项目,并添加 commons-lang3 依赖。

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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.0</version>
        <relativePath/>
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>19</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
登录后复制

主应用类 DemoApplication.java:

package com.example.demo;

import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        String mix = "MIX";
        if (StringUtils.isNoneBlank(mix)) {
            System.out.println(mix);
        }
        SpringApplication.run(DemoApplication.class, args);
    }
}
登录后复制

构建项目后,会在 target 目录下生成 demo-0.0.1-SNAPSHOT.jar 文件,可以直接通过 java -jar target/demo-0.0.1-SNAPSHOT.jar 运行。

2. 使用 jdeps 分析依赖模块

在构建自定义运行时之前,我们需要识别应用程序及其依赖项所需的 JDK 模块。jdeps 工具是实现这一目标的关键。

执行 jdeps target/demo-0.0.1-SNAPSHOT.jar 命令:

jdeps target/demo-0.0.1-SNAPSHOT.jar
demo-0.0.1-SNAPSHOT.jar -> java.base
demo-0.0.1-SNAPSHOT.jar -> java.logging
demo-0.0.1-SNAPSHOT.jar -> not found
   com.example.demo                                   -> java.io                                            java.base
   com.example.demo                                   -> java.lang                                          java.base
   com.example.demo                                   -> org.apache.commons.lang3                           not found
   com.example.demo                                   -> org.springframework.boot                           not found
   com.example.demo                                   -> org.springframework.boot.autoconfigure             not found
   com.example.demo                                   -> org.springframework.context                        not found
   ... (其他 Spring Boot Loader 相关输出) ...
登录后复制

jdeps 输出解读:

  • demo-0.0.1-SNAPSHOT.jar -> java.base 和 demo-0.0.1-SNAPSHOT.jar -> java.logging 表明应用程序直接或间接依赖于 java.base 和 java.logging 这两个 JDK 模块。
  • not found 标识符出现在 org.apache.commons.lang3、org.springframework.boot 等依赖项旁边,这是因为 jdeps 在分析 Spring Boot 的“胖 JAR”时,默认将其内部的第三方库视为未找到的外部模块。对于 jlink 而言,我们主要关注应用程序对 JDK 模块的依赖。
  • 更详细的 jdeps 输出会列出 org.springframework.boot.loader 等内部组件对 java.io, java.lang, java.util 等 java.base 模块内部包的依赖。

从初步分析来看,java.base 和 java.logging 是显而易见的必需模块。

3. 初次尝试 jlink 并分析错误

基于 jdeps 的初步结果,我们尝试构建一个包含 java.base 和 java.logging 的自定义运行时:

jlink --module-path $JAVA_HOME/jmods --add-modules java.base,java.logging --output mycustomrt
登录后复制

这条命令会在当前目录下创建一个名为 mycustomrt 的自定义运行时环境。

现在,尝试使用这个自定义运行时来运行 Spring Boot 应用:

AppMall应用商店
AppMall应用商店

AI应用商店,提供即时交付、按需付费的人工智能应用服务

AppMall应用商店 56
查看详情 AppMall应用商店
mycustomrt/bin/java -jar target/demo-0.0.1-SNAPSHOT.jar
登录后复制

不出所料,应用程序启动失败,并抛出了 java.lang.NoClassDefFoundError: java/beans/PropertyEditorSupport 错误:

java.lang.NoClassDefFoundError: java/beans/PropertyEditorSupport
        at java.base/java.lang.ClassLoader.defineClass1(Native Method)
        at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1013)
        ...
        at org.springframework.boot.context.properties.bind.BindConverter$TypeConverterConverter.<clinit>(BindConverter.java:180)
        ...
Caused by: java.lang.ClassNotFoundException: java.beans.PropertyEditorSupport
        at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:445)
        ...
登录后复制

这个错误非常关键,它表明我们的自定义运行时缺少 java.beans.PropertyEditorSupport 类。java.beans 包中的类通常与 Java 的 JavaBeans 规范相关,虽然它在较旧的 Java 版本中可能部分属于 java.base,但在现代 Java 版本中,尤其是涉及 GUI 或更广泛的工具支持时,它往往归属于 java.desktop 模块。Spring Boot 即使不直接涉及桌面 GUI,其内部的属性绑定、类型转换等机制也可能间接依赖 java.beans 中的一些工具类。

4. 修正 jlink 模块列表

为了解决 NoClassDefFoundError,我们需要将包含 java.beans 包的模块添加到自定义运行时中。经过排查,java.beans.PropertyEditorSupport 位于 java.desktop 模块。

此外,考虑到 Spring Boot 应用的常见需求,一些其他常用模块也可能被间接依赖,例如:

  • java.xml: 用于 XML 处理,Spring 框架中常用。
  • java.sql: 用于数据库连接和操作。
  • java.prefs: 用于用户偏好设置。

因此,我们将这些常用且可能被 Spring Boot 间接依赖的模块一并加入。

修正后的 jlink 命令:

jlink --module-path $JAVA_HOME/jmods --add-modules java.base,java.logging,java.xml,java.sql,java.prefs,java.desktop --output mycustomrt
登录后复制

执行此命令后,一个新的 mycustomrt 运行时环境将被创建。

5. 验证自定义运行时

现在,再次使用新生成的自定义运行时来运行 Spring Boot 应用:

mycustomrt/bin/java -jar target/demo-0.0.1-SNAPSHOT.jar
登录后复制

此时,应用程序应该能够成功启动并正常运行,输出 Spring Boot 的启动日志和应用程序的自定义消息:

MIX
  .   ____          _            __ _ _
 /\ / ___'_ __ _ _(_)_ __  __ _    
( ( )___ | '_ | '_| | '_ / _` |    
 \/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |___, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.0.0)

2022-11-30T19:47:53.468+01:00  INFO 18179 --- [           main] com.example.demo.DemoApplication         : Starting DemoApplication v0.0.1-SNAPSHOT using Java 19.0.1 with PID 18179 (/home/me/NetBeansProjects/demo/target/demo-0.0.1-SNAPSHOT.jar started by neblaz in /home/me/NetBeansProjects/demo)
... (其他 Spring Boot 启动日志) ...
登录后复制

这表明我们已经成功为 Spring Boot 3.0 应用构建了一个功能完整的自定义运行时环境。

6. 注意事项与最佳实践

  • 迭代式模块发现: 对于复杂的 Spring Boot 应用,仅凭 jdeps 的一次运行可能无法完全列出所有必需的 JDK 模块。通常需要一个迭代过程:先添加最基本的模块,运行应用,根据 NoClassDefFoundError 提示补充缺失的模块,直到应用正常启动。
  • Spring Boot Fat Jar 的特殊性: Spring Boot 的可执行 JAR 是一个“胖 JAR”,它包含了所有应用程序代码和依赖项。jlink 创建的运行时环境只包含 JDK 模块,而应用程序的第三方依赖仍然由 Spring Boot 的内部加载器处理。
  • 更全面的 jdeps 用法: 对于更深入的模块依赖分析,可以尝试 jdeps --recursive --list-deps target/demo-0.0.1-SNAPSHOT.jar 或 jdeps --list-modules --recursive target/demo-0.0.1-SNAPSHOT.jar。然而,对于胖 JAR,这些命令可能仍然无法完全自动化地识别所有间接 JDK 模块依赖,因为它们主要关注 JAR 文件本身的模块信息,而非运行时反射或动态加载的需求。
  • 自动化构建: 在实际项目中,建议将 jlink 过程集成到 Maven 或 Gradle 构建生命周期中,例如使用 maven-jlink-plugin 或 gradle-jlink-plugin,以自动化自定义运行时镜像的生成。
  • GraalVM Native Image: 对于追求极致启动速度和更小部署包的应用,可以考虑使用 GraalVM Native Image 技术。它能将 Spring Boot 应用编译成独立的本地可执行文件,进一步减小体积并显著提升启动速度,但配置过程相对复杂。

总结

通过本教程,我们学习了如何利用 jlink 工具为 Spring Boot 3.0 应用构建精简的自定义运行时环境。关键步骤包括:

  1. 使用 jdeps 分析应用程序对 JDK 模块的初步依赖。
  2. 尝试构建初始运行时并运行应用程序。
  3. 根据运行时错误(如 NoClassDefFoundError)识别并补充缺失的 JDK 模块。
  4. 重新构建运行时并验证应用程序的正常运行。

通过这种方式,开发者可以为 Spring Boot 应用创建更小、更高效的部署包,这对于优化资源利用和提升部署效率具有重要意义。

以上就是使用 jlink 为 Spring Boot 3.0 应用构建自定义运行时环境的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号