GraalVM与Java静态编译:原理与应用
上QQ阅读APP看书,第一时间看更新

4.4 预执行目标应用程序

由1.3.3节可知,Java语言的动态特性违反了静态编译的封闭性假设。GraalVM允许通过配置的形式将缺失的信息补充给静态编译器以满足封闭性,为此GraalVM设计了reflect-config.json、jni-config.json、resource-config.json、proxy-config.json、serialization-config.json和predefined-classes-config.json这6个json格式的配置文件,分别用于向静态编译提供反射目标信息、JNI回调目标信息、资源文件信息、动态代理目标接口信息、序列化信息和提前定义的动态类信息。静态编译框架会根据用户提供的配置信息,从编译时的classpath上寻找对应的元素,并将它们编译到最后的产物中,从而实现封闭性。

虽然json格式本身是便于人阅读和修改的,但是通过人工的方式为一个实际应用程序填写配置并不现实,一是因为动态特性的使用量可能会很大,人工配置费时费力还容易遗漏;二是因为开发人员也未必清楚每一处动态特性的详细信息,尤其是第三方库和框架里的场景。因此GraalVM在native-image的可选安装包里提供了基于JVMTI(JVM Tool Interface)的native-image-agent,用于挂载到应用程序上,在运行时监控并记录与这些动态特性相关的函数调用信息。本书将在开始静态编译之前运行带有native-image-agent的目标应用程序,使其自动生成配置文件的过程,称为预执行。

预执行只需在目标应用程序原本的启动命令基础上,添加如下加粗的参数启动Agent即可。在目标应用程序执行完毕后,配置文件会输出到由config-output-dir=指定的位置。

$GRAALVM_HOME/bin/java -cp $CP -agentlib:native-image-agent=config-output-dir=$CONFIG_ROOT/META-INF/native-image AppMain

预执行的命令需要注意两点。

1)启动Agent必须使用GraalVM JDK的java(指JDK启动器),因为所需的native-image-agent是GraalVM JDK的独有特性,其他JDK中没有该工具。

2)由config-output-dir参数设置的配置文件输出目录虽然可以是任意路径,但是为了便于配置稍后的编译命令,推荐按照此例输出到$CONFIG_ROOT/META-INF/native-image目录中。其中$CONFIG_ROOT可以任意指定,但META-INF/native-image是固定模式,因为静态编译框架会默认从classpath的META-INF/native-image目录中读取配置文件。所以只要编译时将$CONFIG_ROOT加到classpath上,静态编译框架就会自动识别出配置文件。

native-image-agent还提供了多种参数用于更详细地控制记录过程。本书在第14章介绍native-image-agent的实现原理时再对这些参数进行更详细的介绍和说明,一般情况下只使用本节介绍的config-output-dir就足以应对。

在编译时静态编译框架会自动从classpath的META-INF/native-image目录结构中识别出配置文件,此外,用户可以在启动native-image时传入多个参数以额外指定配置文件的位置。

1)-H:ConfigurationFileDirectories=:指定配置文件的直接目录,多个项目之间用逗号分隔。在该目录中按默认方式命名的json配置文件都可以被自动识别。

2)-H:ConfigurationResourceRoots=:指定配置资源的根路径,多个项目之间用逗号分隔。配置文件不仅可以被当作外部文件读取,也可以被当作resource资源读取。这种方式特别适用于读取存放在jar文件中的配置文件。

3)-H:XXXConfigurationFiles=:指定某一种类型的配置文件,多个项目之间用逗号分隔。这里的XXX可以是Reflection、DynamicProxy、Serialization、SerializationDeny、Resource、JNI或PredefinedClasses。

4)-H:XXXConfigurationResources=:指定某一种类型的配置资源的路径,多个项目之间用逗号分隔。这里的XXX可以是Reflection、DynamicProxy、Serialization、SerializationDeny、Resource、JNI或PredefinedClasses。