Spark FrameworkをGraalVMでネイティブコンパイルしてみます。
- maven-assembly-pluginでfat jarをつくる
- native-imageに--report-unsupported-elements-at-runtimeをつけてだまらせる
という感じで。
SparkFrameworkのdependencyを登録します。
<dependency> <groupId>com.sparkjava</groupId> <artifactId>spark-core</artifactId> <version>2.8.0</version> </dependency>
Fat Jarをつくるためにmaven-assembly-pluginを登録します
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <version>3.1.0</version> <configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> <archive> <manifest> <mainClass>kis.sparksample.MySpark</mainClass> </manifest> </archive> </configuration> <executions> <execution> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
こんな感じの処理を書いてみます。
package kis.sparksample; import static spark.Spark.*; public class MySpark { public static void main(String[] args) { get("/hello", (req, res) -> "Hello World"); } }
native-imageしてみるとエラーが出ました
jdk $GRAALVM_HOME/bin/native-image -jar $SOURCE/target/SparkSample-1.0-SNAPSHOT-jar-with-dependencies.jar Build on Server(pid: 92849, port: 51657) [SparkSample-1.0-SNAPSHOT-jar-with-dependencies:92849] classlist: 706.16 ms [SparkSample-1.0-SNAPSHOT-jar-with-dependencies:92849] (cap): 1,710.59 ms [SparkSample-1.0-SNAPSHOT-jar-with-dependencies:92849] setup: 2,089.39 ms SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. [SparkSample-1.0-SNAPSHOT-jar-with-dependencies:92849] analysis: 7,770.54 ms error: Error loading a referenced type: java.lang.reflect.InvocationTargetException Detailed message: Error: Error loading a referenced type: java.lang.reflect.InvocationTargetException Trace: at parsing org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:418) Call path from entry point to org.slf4j.LoggerFactory.getILoggerFactory(): at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:408) at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:357) at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:383) ...
原因をみてみようと、--report-unsupported-elements-at-runtimeをつけてみます
jdk $ $GRAAL_HOME/bin/native-image --report-unsupported-elements-at-runtime -jar $SOURCE/target/SparkSample-1.0-SNAPSHOT-jar-with-dependencies.jar Build on Server(pid: 92849, port: 51657) [SparkSample-1.0-SNAPSHOT-jar-with-dependencies:92849] classlist: 557.25 ms [SparkSample-1.0-SNAPSHOT-jar-with-dependencies:92849] (cap): 1,513.05 ms [SparkSample-1.0-SNAPSHOT-jar-with-dependencies:92849] setup: 1,764.90 ms SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. [SparkSample-1.0-SNAPSHOT-jar-with-dependencies:92849] (typeflow): 3,893.53 ms [SparkSample-1.0-SNAPSHOT-jar-with-dependencies:92849] (objects): 3,937.29 ms [SparkSample-1.0-SNAPSHOT-jar-with-dependencies:92849] (features): 166.68 ms [SparkSample-1.0-SNAPSHOT-jar-with-dependencies:92849] analysis: 8,284.49 ms [SparkSample-1.0-SNAPSHOT-jar-with-dependencies:92849] universe: 399.41 ms [SparkSample-1.0-SNAPSHOT-jar-with-dependencies:92849] (parse): 850.16 ms [SparkSample-1.0-SNAPSHOT-jar-with-dependencies:92849] (inline): 1,226.09 ms [SparkSample-1.0-SNAPSHOT-jar-with-dependencies:92849] (compile): 7,422.96 ms [SparkSample-1.0-SNAPSHOT-jar-with-dependencies:92849] compile: 10,158.63 ms [SparkSample-1.0-SNAPSHOT-jar-with-dependencies:92849] image: 1,358.09 ms [SparkSample-1.0-SNAPSHOT-jar-with-dependencies:92849] write: 706.80 ms [SparkSample-1.0-SNAPSHOT-jar-with-dependencies:92849] [total]: 23,271.43 ms
通ってしまった。
動かす
jdk $ ./SparkSample-1.0-SNAPSHOT-jar-with-dependencies
サイズは15MBくらい。
jdk $ ls -l SparkSample-1.0-SNAPSHOT-jar-with-dependencies -rwxr-xr-x 1 kishida staff 15266396 11 14 19:46 SparkSample-1.0-SNAPSHOT-jar-with-dependencies
SLF4Jまわりのリフレクションを設定すればよさそうだけど、とりあえずこれで。