提出问题
GraalVM 将 Java 程序编译成可执行文件,反射功能无法使用
使用 log4j 后,可以正常编译,但执行报错
maven 工程 使用log4j
pom.xml
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
java
package webserver;
import org.apache.log4j.Logger;
public class Log4jStd {
static final Logger LOGGER= Logger.getLogger(Test.class);
public static void main(String[] args) {
LOGGER.info("Hello world");
}
}
分析
Graalvm通过静态分析提前编译来为Java应用程序构建高度优化的本机可执行文件,需要在 编译时就知道所有的程序类型,而java中的反射、动态代理等功能,在编译时不确定具体的类型,所以在使用GraalVm构建native image前需要通过配置列出反射可见的所有类型。
解决
graavm提供 agent工具,该工具会生成整个代码中需要用到反射的配置文件
实现方式一
- 将项目打成jar包
- 根据 jar 包,生成需要用到反射的配置文件
- 编译成可执行文件
将项目打成jar包
plugin插件
pom.xml
中增加下面 plugin
:
<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>webserver.Log4jStd</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
生成 jar
在 idea 上点击 packeage
生成jar包
结果如下:
生成需要用到反射的配置文件
执行下面命令
java -agentlib:native-image-agent=config-output-dir=D:\java\graalvm_std\src\main\resources\META-INF\native-image -jar D:\java\graalvm_std\target\graalvm_std-1.0-SNAPSHOT.jar
解释:
java -agentlib:native-image-agent=config-output-dir=resources目录\META-INF\native-image -jar jar文件名
resources目录\META-INF\native-image
:maven 工程,配置文件必须在resources
下target目录\.jar文件名
:上面生成 jar文件路径
执行结果1
从控制台可以看出,相当于执行 java -jar xxx.jar
,也就是正常执行 .jar
程序
注意(关键)
一定要确保正常执行 .jar
程序,不能因为缺少配置文件、启动参数不正确等原因,导致报错、终止运行,这种情况导致下一步生成的 二进制可执行文件 不能正常运行
执行结果2
生成配置文件: reflect-config.json
,内容如下:
[
{
"name":"java.beans.PropertyVetoException"
},
{
"name":"java.lang.Object",
"queryAllPublicMethods":true
},
{
"name":"java.lang.String"
},
{
"name":"java.lang.Thread",
"methods":[{"name":"getContextClassLoader","parameterTypes":[] }]
},
{
"name":"org.apache.log4j.Appender"
},
{
"name":"org.apache.log4j.Category"
},
{
"name":"org.apache.log4j.ConsoleAppender",
"methods":[{"name":"<init>","parameterTypes":[] }]
},
{
"name":"org.apache.log4j.Layout",
"queryAllPublicMethods":true
},
{
"name":"org.apache.log4j.Logger"
},
{
"name":"org.apache.log4j.PatternLayout",
"queryAllPublicMethods":true,
"methods":[
{"name":"<init>","parameterTypes":[] },
{"name":"setConversionPattern","parameterTypes":["java.lang.String"] }
]
},
{
"name":"org.apache.log4j.helpers.Loader"
},
{
"name":"org.apache.log4j.spi.OptionHandler"
}
]
编译成可执行文件-方式一
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>
<!-- 构建独立镜像或报告故障 -->
--no-fallback
</buildArgs>
</configuration>
</plugin>
参数解释:https://www.graalvm.org/22.0/reference-manual/native-image/Options/
命令
在工程根目录下执行下面命令:
mvn -Pnative clean package
生成文件如下:
除了可执行文件,还有其他文件,亲测,有时不需要其他文件,仅可执行文件,就可以执行
编译成可执行文件-方式二
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>
<!-- 构建独立镜像或报告故障 -->
--no-fallback
</buildArgs>
</configuration>
</plugin>
参数解释:https://www.graalvm.org/22.0/reference-manual/native-image/Options/
package
通过 idea 的 maven 执行 package 命令,即可生成(但可能有问题)
方式二
依赖
在 pom.xml 中的 <buildArgs>
配置 --initialize-at-build-time
,表示 在映像构建期间初始化的包和类
如何知道有哪些配置,目前网上没有资料,解决方法是:
在 idea 上点击 packeage
生成可执行文件时,会报错,将报错的类添加进去
<build>
<plugins>
<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>
<!-- 构建独立镜像或报告故障 -->
--no-fallback
<!-- 在映像构建期间初始化的包和类 -->
--initialize-at-build-time=org.apache.log4j.PatternLayout
--initialize-at-build-time=org.apache.log4j.Logger
--initialize-at-build-time=org.apache.log4j.helpers.LogLog
--initialize-at-build-time=org.apache.log4j.LogManager
--initialize-at-build-time=org.apache.log4j.helpers.Loader
-H:+ReportExceptionStackTraces
</buildArgs>
</configuration>
</plugin>
</plugins>
</build>
生成
在 idea 上点击 packeage
生成可执行文件时
参考:
https://www.cnblogs.com/cfas/p/16339789.html
https://blog.csdn.net/weixin_44123053/article/details/120486756