GraalVM 将 Java 程序编译成可执行文件,读取resource目录下文件(maven 工程)

提出问题

GraalVM 将 Java 程序编译成可执行文件,但 无法读取 resource 目录下的文件

例子

创建 maven 工程

index.html

在 resource 目录下创建 index.html 文件,内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>%s</title>
</head>
<body>
    <pre>%s</pre>
</body>
</html>

java代码

读取上面的 index.html 文件

package test;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) throws IOException {
        InputStream is=Main.class.getResourceAsStream("/index.html");
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        String line;
        while( (line = br.readLine()) !=null){
            System.out.println(line);
        }
        br.close();
        is.close();

    }
}

执行结果

java代码可以正常读取,但编译成 .exe 文件后,读取 resources 目录下的文件报错

解决

graavm提供 agent工具,该工具会分析 resources 目录下的文件,并生成到 resource-config.json 配置文件中

操作步骤

  1. 将项目打成jar包
  2. 通过命令,将 resources 目录下的文件生成到 resource-config.json 配置文件中
  3. 编译成可执行文件

第一步:将项目打成jar包

plugin插件

pom.xml 中增加下面 plugin:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.2.4</version>
            <executions>
                <execution>
                    <id>package-jar</id>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <transformers>
                            <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <!-- 主启动类 -->
                                <mainClass>test.Main</mainClass>
                            </transformer>
                        </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

生成 jar

在 idea 上点击 packeage 生成jar包

结果如下:

第二步:生成配置文件

提示:如果没有修改依赖、不需要读取 resources 目录,不需要此步骤

在 target 目录下,执行下面命令

java -agentlib:native-image-agent=config-output-dir=..\src\main\resources\META-INF\native-image  -jar  graalvm_std-1.0-SNAPSHOT.jar

解释:

java -agentlib:native-image-agent=config-output-dir=resources目录\META-INF\native-image  -jar  fat jar文件名
  • resources目录\META-INF\native-image:maven 工程,生成的配置文件必须在 resources 下

  • fat jar文件名:上面生成 jar文件名,必须是 fat包

执行结果1

从控制台可以看出,相当于执行 java -jar xxx.jar,也就是正常执行 .jar 程序

注意(关键)

一定要确保正常执行 .jar 程序,不能因为缺少配置文件、启动参数不正确等原因,导致报错、终止运行,这种情况导致下一步生成的 二进制可执行文件 不能正常运行

执行结果2

生成配置文件: resource-config.json,内容如下:

{
  "resources":{
  "includes":[{
      "pattern":"\\Qindex.html\\E"
    }]},
  "bundles":[]
}

第三步:编译成可执行文件

plugin插件

注释掉上面的plugin,加上下面的plugin:

<plugin>
    <groupId>org.graalvm.nativeimage</groupId>
    <artifactId>native-image-maven-plugin</artifactId>
    <version>21.2.0</version>
    <executions>
        <execution>
            <goals>
                <goal>native-image</goal>
            </goals>
            <phase>package</phase>
        </execution>
    </executions>
    <configuration>
        <!-- imageName用于设置生成的二进制文件名称 -->
        <imageName>test</imageName>
        <!-- mainClass用于指定main方法类路径 -->
        <mainClass>webserver.Log4jStd</mainClass>
        <!-- native image 编译参数文档:https://docs.oracle.com/en/graalvm/enterprise/20/docs/reference-manual/native-image/NativeImageMavenPlugin/ -->
        <buildArgs>
            <!-- 构建独立的可执行文件,不依赖jdk -->
            --no-fallback

        </buildArgs>
    </configuration>
</plugin>

参数解释:https://www.graalvm.org/22.0/reference-manual/native-image/Options/

编译成可执行文件-方式一

在 工程根目录下 执行下面命令:

mvn -Pnative clean package

生成文件如下:

除了可执行文件,还有其他文件,亲测,有时不需要其他文件,仅可执行文件,就可以执行

编译成可执行文件-方式二(简单)

通过 idea 的 maven 执行 package 命令,即可生成

提示:可能有问题

参考:
https://www.cnblogs.com/cfas/p/16339789.html
https://blog.csdn.net/weixin_44123053/article/details/120486756


原文出处:/show_1IX5qkT6XJfr.html