相容性與保護範圍
P4JX 會加密儲存受保護類別的方法實作,並且只允許隨包的 VLX JRE 在執行時讀取。為了在保護強度與框架相容性之間取得平衡,建議只保護核心商業邏輯,把框架進入點、DTO 與實體、需要由框架在執行時動態產生或修改的類別,以及第三方相依套件排除在保護範圍之外。
1. 先執行相容性掃描
只掃描,不產生輸出:
p4j javaapp app.jar --compat-scan
p4j springboot app.jar --compat-scan
p4j tomcat app.war --compat-scan
掃描並套用保守建議:
p4j springboot app.jar dist --compat-apply
你明確指定的選項,優先權一律高於自動建議。掃描屬於靜態啟發式分析:報告中出現「需要複查」,不代表應用程式一定會出問題;報告沒有發現問題,也不能取代在目標平臺上的迴歸測試。
掃描結果要求修改程式碼時
如果 GUI 報告顯示需要處理(英文介面為 ACTION REQUIRED),表示必須修改應用程式原始碼,這類問題無法靠調整打包參數解決。報告會列出涉及的具體類別與方法,並給出以下其中一類建議:
- 從記憶體讀取 ZIP 或 JAR:把
ByteArrayInputStream改成以檔案為基礎的讀取方式,例如Files.newInputStream(Path)、FileInputStream、ZipFile或JarFile。 - 從原始位元組定義類別:不要對受保護的類別直接呼叫
ClassLoader#defineClass,改用Class.forName()或ClassLoader.loadClass(),讓 P4JX 執行時完成類別載入。
修改原始碼後重新建置 JAR 或 WAR,再執行一次相容性掃描;確認報告中不再出現該問題,才產生保護包。
2. 建議的保護模型
公開邊界/框架進入點 → 一般 facade 或介面 → 受保護的核心實作
範例:
--protect 'com.example.service.impl.**' \
--exclude 'com.example.dto.**,com.example.config.**'
3. 通常不應保護的類別
- 控制器、Servlet、Filter、Listener、Advice;
- Spring 設定類別,以及經 AOT 或 CGLIB 增強的物件;
- Jackson DTO、record、JPA 實體、序列化模型;
- JNI、SWT 等原生橋接類別;
- 由 Agent、ORM、Mock 框架、熱重載或自訂 ClassLoader 改寫或重新定義的類別;
- 第三方框架與開放原始碼相依套件;
- 需要讀取自身真實 class 位元組碼的類別。
4. 不支援或受限的 JVM 能力
執行環境
- 受保護的應用程式必須使用隨包的 VLX JRE 執行;
- 不支援 JPMS 的
-m啟動方式,也不支援單一原始檔啟動; - 類別路徑上的一般 JAR 必須由打包器登錄,不能在部署時任意追加;
- 不要用 VLX JRE 去執行未受保護的一般應用程式。
除錯與 Agent
- 不支援 JVMTI、JDWP 除錯器、效能分析器、覆蓋率工具,以及多數 APM agent;
- 不支援
-javaagent、-agentlib、熱重載與類別重新定義; - 需要位元組碼織入的處理,必須在編碼之前完成。
啟動最佳化
- 不支援 CDS、AppCDS 與 AOT;
- ZGC 與 Shenandoah GC 不在 P4JX 執行時的支援範圍內。
5. 類別資源與掃描器
讀取受保護類別的 .class 資源時,得到的是中繼資料樁:類別名稱、簽章與註解都會保留,但不含真實的方法主體。
- 一般反射可以讀到中繼資料,但無法還原原始位元組碼;
- 自行解析實體 ZIP 的工具,預設看不到 P4JX 歸檔中的內容,可以嘗試
--zip-overlay scanner; - ClassGraph、Reflections 這類類別路徑掃描器,在 Spring Boot 下可能需要搭配
--layout fat; - 不支援以
ZipInputStream或JarInputStream從記憶體串流、網路串流中解析 P4JX 歸檔; - zipfs 檢視是唯讀的,無法透過它修改歸檔。
6. 歸檔行為
.jar字尾並不代表它是一般 JAR,內容仍然是 P4JX;- Multi-Release JAR 會在編碼時依目標 Java 版本攤平;
- 原 JAR 的簽章與憑證語意不會保留,如果散布環節有要求,請對最終交付物另行簽章;
- 不要修改、重新壓縮或合併產生的 P4JX 檔案。