未找到 Jdeps 模块 java.annotation

Jdeps Module java.annotation not found

我正在尝试使用 jdeps 和 jlink 为 Spring 引导微服务创建一个最小的 jre,但是当我使用 jdeps 部分时出现以下错误

Exception in thread "main" java.lang.module.FindException: Module java.annotation not found, required by org.apache.tomcat.embed.core
    at java.base/java.lang.module.Resolver.findFail(Resolver.java:893)
    at java.base/java.lang.module.Resolver.resolve(Resolver.java:192)
    at java.base/java.lang.module.Resolver.resolve(Resolver.java:141)
    at java.base/java.lang.module.Configuration.resolve(Configuration.java:421)
    at java.base/java.lang.module.Configuration.resolve(Configuration.java:255)
    at jdk.jdeps/com.sun.tools.jdeps.JdepsConfiguration$Builder.build(JdepsConfiguration.java:564)
    at jdk.jdeps/com.sun.tools.jdeps.JdepsTask.buildConfig(JdepsTask.java:603)
    at jdk.jdeps/com.sun.tools.jdeps.JdepsTask.run(JdepsTask.java:557)
    at jdk.jdeps/com.sun.tools.jdeps.JdepsTask.run(JdepsTask.java:533)
    at jdk.jdeps/com.sun.tools.jdeps.Main.main(Main.java:49)

我已经尝试了以下命令但没有效果

jdeps --ignore-missing-deps --multi-release 17 --module-path target/lib/* target/errorrr-*.jar
jdeps --multi-release 16 --module-path target/lib/* target/errorrr-*.jar
jdeps --ignore-missing-deps --multi-release 17 --class-path target/lib/* target/errorrr-*.jar

我已经用 java 版本 11、16 和 17 以及 Spring Boot 的不同版本进行了尝试。

当我 运行 mvn install

时,maven-dependency-plugin 插件将构建所需的所有依赖项复制到 target/lib 文件夹

在确定负责任的依赖关系后,我从头开始创建了一个新项目,仅用它来隔离错误,但它仍然存在。

我一开始尝试使用 gradle 但由于错误仍然存​​在,我将其更改为 mavem 但也没有改变。

当我添加所请求的指定依赖项时,错误更改为

#13 1.753 Exception in thread "main" java.lang.Error: java.util.concurrent.ExecutionException: com.sun.tools.jdeps.MultiReleaseException
        #13 1.753       at jdk.jdeps/com.sun.tools.jdeps.DependencyFinder.waitForTasksCompleted(DependencyFinder.java:271)
        #13 1.753       at jdk.jdeps/com.sun.tools.jdeps.DependencyFinder.parse(DependencyFinder.java:133)
        #13 1.753       at jdk.jdeps/com.sun.tools.jdeps.DepsAnalyzer.run(DepsAnalyzer.java:129)
        #13 1.753       at jdk.jdeps/com.sun.tools.jdeps.ModuleExportsAnalyzer.run(ModuleExportsAnalyzer.java:74)
        #13 1.753       at jdk.jdeps/com.sun.tools.jdeps.JdepsTask$ListModuleDeps.run(JdepsTask.java:1047)
        #13 1.753       at jdk.jdeps/com.sun.tools.jdeps.JdepsTask.run(JdepsTask.java:574)
        #13 1.753       at jdk.jdeps/com.sun.tools.jdeps.JdepsTask.run(JdepsTask.java:533)
        #13 1.753       at jdk.jdeps/com.sun.tools.jdeps.Main.main(Main.java:49)
        #13 1.753 Caused by: java.util.concurrent.ExecutionException: com.sun.tools.jdeps.MultiReleaseException
        #13 1.753       at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122)
        #13 1.753       at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191)
        #13 1.753       at jdk.jdeps/com.sun.tools.jdeps.DependencyFinder.waitForTasksCompleted(DependencyFinder.java:267)
        #13 1.754       ... 7 more
        #13 1.754 Caused by: com.sun.tools.jdeps.MultiReleaseException
        #13 1.754       at jdk.jdeps/com.sun.tools.jdeps.VersionHelper.add(VersionHelper.java:62)
        #13 1.754       at jdk.jdeps/com.sun.tools.jdeps.ClassFileReader$JarFileReader.readClassFile(ClassFileReader.java:360)
        #13 1.754       at jdk.jdeps/com.sun.tools.jdeps.ClassFileReader$JarFileIterator.hasNext(ClassFileReader.java:402)
        #13 1.754       at jdk.jdeps/com.sun.tools.jdeps.DependencyFinder.lambda$parse(DependencyFinder.java:179)
        #13 1.754       at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
        #13 1.754       at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
        #13 1.754       at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
        #13 1.754       at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
        #13 1.754       at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
        #13 1.754       at java.base/java.lang.Thread.run(Thread.java:833)

我的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>2.6.0</version>
       <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.example</groupId>
   <artifactId>errorrr</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>errorrr</name>
   <description>Demo project for Spring Boot</description>
   <properties>
       <java.version>17</java.version>
   </properties>
   <dependencies>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
       </dependency>

       <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>

   </dependencies>

   <build>
       <plugins>
           <plugin>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-maven-plugin</artifactId>
           </plugin>
           <plugin>
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-dependency-plugin</artifactId>
               <executions>
                   <execution>
                       <id>copy-dependencies</id>
                       <phase>package</phase>
                       <goals>
                           <goal>copy-dependencies</goal>
                       </goals>
                       <configuration>
                           <outputDirectory>${project.build.directory}/lib</outputDirectory>
                       </configuration>
                   </execution>
               </executions>
           </plugin>
       </plugins>
   </build>

</project>

如果我不需要使用这个依赖项,我可以完成所有的构建过程,最后我有一个 76mb 的 jre

我一直在为我的 gradle spring 引导项目中的类似问题而苦苦挣扎 我正在使用以下输出在我的 dockerfile 中的 jlink 中添加模块 (openjdk:17-alpine):

RUN jdeps \
    --ignore-missing-deps \
    -q \
    --multi-release 17 \
    --print-module-deps \
    --class-path build/lib/* \
    app.jar > deps.info

RUN jlink --verbose \
    --compress 2 \
    --strip-java-debug-attributes \
    --no-header-files \
    --no-man-pages \
    --output jre \
    --add-modules $(cat deps.info)

我认为只要您拥有所有必需的依赖项,您的 mvn 构建就可以了。但以防万一我修改了我的 gradle jar 任务以包含如下依赖项:

jar {
     manifest {
          attributes "Main-Class": "com.demo.Application"
     }
     duplicatesStrategy = DuplicatesStrategy.INCLUDE
     from {
          configurations.default.collect { it.isDirectory() ? it : zipTree(it) 
     }
   }
}

我找到了一个有效但不完美但可以正常工作的解决方案。 在我的例子中,lib“jackson”是问题的原因。它使用 java 多版本,并且在 jdeps 期间以某种方式导致了一些错误。 经过一些测试后,我明白我可以从评估中删除这个库,并且 deps.info 中不会缺少任何模块。 我需要添加此任务以进行删除:

task myDeleteTask(type: Delete) {
    delete files("${buildDir}/temp-lib/jackson-databind-{your_version}.jar")
    delete files("${buildDir}/temp-lib/jackson-datatype-jdk8-{your_version}.jar")
    delete files("${buildDir}/temp-lib/jackson-datatype-jsr310-{your_version}.jar")
    delete files("${buildDir}/temp-lib/jackson-module-parameter-names-{your_version}.jar")
    delete files("${buildDir}/temp-lib/jackson-core-{your_version}.jar")
    delete files("${buildDir}/temp-lib/jackson-dataformat-cbor-{your_version}.jar")
}
task tempCopyDependencies(type: Copy) {
    from configurations.runtimeClasspath
    into "$buildDir/temp-lib"
}

tasks.named("build"){
    finalizedBy("tempCopyDependencies")
    finalizedBy("myDeleteTask")
}

OBS:题中我用maven是因为比较简单,知识面也比较广,但是我的实际项目用的是gradle,这样删除任务就更容易了

我遇到了类似的问题,对我的情况有所帮助 - 指定 --class-path--module-path 都指向与库相同的目录。 根据你的例子,我觉得应该是jdeps --ignore-missing-deps --print-module-deps --multi-release 17 --module-path="target/lib/*" --class-path="target/lib/*" target/errorrr-*.jar.

此外,jdeps 来自 JDK 17(可能还有更早的版本)。它似乎已在 JDK 18 中修复,至少它对我来说没有任何问题。

使用 Docker 您可以进行分阶段构建,首先使用 JDK 18 识别依赖项,然后使用 JDK 17 构建新的 JRE 映像。像这样:

FROM amazoncorretto:18-alpine as deps

COPY ./app.jar /app/app.jar
RUN mkdir /app/unpacked && \
    cd /app/unpacked && \
    unzip ../app.jar && \
    cd .. && \
    $JAVA_HOME/bin/jdeps \
    --ignore-missing-deps \
    --print-module-deps \
    -q \
    --recursive \
    --multi-release 17 \
    --class-path="./unpacked/BOOT-INF/lib/*" \
    --module-path="./unpacked/BOOT-INF/lib/*" \
    ./app.jar > /deps.info

FROM amazoncorretto:17.0.3-alpine as corretto-jdk

RUN apk add --no-cache binutils

COPY --from=deps /deps.info /deps.info

RUN $JAVA_HOME/bin/jlink \
    --verbose \
    --add-modules $(cat /deps.info) \
    --strip-debug \
    --no-man-pages \
    --no-header-files \
    --compress=2 \
    --output /customjre

您可以在此处查看完整示例:https://github.com/monosoul/jvm-in-docker/blob/main/jre-slim-auto.dockerfile

对于任何感兴趣的人,这里有一篇关于使用 jlinkjdeps 的博客文章:https://blog.monosoul.dev/2022/04/25/reduce-java-docker-image-size/