GraalVM Native Image of Java Swing app
GraalVM Native Image可以將Java應用程序編譯為binary執行檔,不需要依賴JRE就可以運行,有啟動速度快和佔用記憶體較少的特點。GraalVM 21.0開始增加了對AWT和Swing的實驗性支持,雖然Java GUI應用程序不像Web應用程序受歡迎,但是我對於可以編寫一些有趣的桌面應用,並且能夠更簡單的分發給其他人使用,還是覺得是一件很棒的事!
準備環境
- GraalVM Community 21.1.0 based on OpenJDK 8
- 下載GraalVM JDK並解壓縮
- 設定系統環境變數
- JAVA_HOME:GraalVM的根目錄
- PATH:GraalVM的bin目錄
- GraalVM預設沒有安裝Native Image功能,需在命令列工具cmd執行下列指令
gu install native-image
- Microsoft Visual C++ (MSVC) Community 2019
- 下載Visual Studio 2019社群版
- 安裝過程選擇C++的桌面開發環境
建置
Native Image在編譯時期就要知道應用程序在執行期間所有會用到的類和方法,這也是執行Java從just-in-time (JIT)變成ahead-of time (AOT)的一種新方式,所以動態加載類、反射機制等要另外提供JSON的配置檔來告訴native-image工具關於該類的附加資訊,自己撰寫這樣的配置是很煩人的事,因此我們可以用GraalVM提供的一個javaagent來跟蹤紀錄應用程序運行時反射和JNI調用的情況,並在應用程序結束時自動生成配置文件
以下是一個簡單的HelloWorld Swing應用程序示例
package com.ryan.main;
import java.awt.EventQueue;
import javax.swing.JFrame;
import java.awt.Label;
public class MainApp {
private JFrame frmSwingNative;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MainApp window = new MainApp();
window.frmSwingNative.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public MainApp() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frmSwingNative = new JFrame();
frmSwingNative.setTitle("Java Swing Native");
frmSwingNative.setResizable(false);
frmSwingNative.setBounds(100, 100, 450, 300);
frmSwingNative.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frmSwingNative.getContentPane().setLayout(null);
Label label = new Label("Hello, World!");
label.setBounds(156, 99, 111, 30);
frmSwingNative.getContentPane().add(label);
}
}
先打包成可執行的JAR檔後,開啟Visual Studio 2019的x64 Native Tools Command Prompt執行下列指令
java -agentlib:native-image-agent=config-output-dir=config -jar swing-native.jar
關閉應用程序後會在config目錄寫入所需的JSON檔,接著執行下列命令會產生系統原生exe執行檔,不是像Launch4j做出來的前導程序而已,這可能需要幾分鐘
native-image -H:ConfigurationFileDirectories=config --no-fallback -jar swing-native.jar MainApp
結果
接著令人興奮的事發生了,執行Java應用程序不再需要bundle JRE,而且啟動的更快,以這個簡單的Swing程序來說幾乎是瞬間,不過需要注意的如果是比較複雜的程序,在native-image-agent運行期間沒有使用到某些UI功能,就無法檢測到JNI/反射的調用而生成不夠完整的配置文件,最後執行程式可能就會發生NoSuchMethodError,所以實際情況還是會需要手動檢查和修改自動生成的配置檔
補充
預設這樣編譯出的exe執行檔會是一個console application,啟動的時候還會多跑出一個command window,這不是我們想要的完美結果,這時候可以再利用下列指令,就可以把我們的exe轉成一個真正的GUI application了
editbin /subsystem:windows MainApp.exe