兼容性与保护范围

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)FileInputStreamZipFileJarFile 等基于文件的读取方式。
  • 从原始字节定义类:不要对受保护类直接调用 ClassLoader#defineClass,改用 Class.forName()ClassLoader.loadClass(),让 P4JX 运行时完成类加载。

修改源码后,重新构建 JAR/WAR,再次执行兼容性扫描;确认报告不再列出该问题后,再生成保护包。

2. 推荐保护模型

公开边界/框架入口 → 普通 facade 或接口 → 受保护核心实现

示例:

--protect 'com.example.service.impl.**' \
--exclude 'com.example.dto.**,com.example.config.**'

3. 通常不应保护的类

  • Controller、Servlet、Filter、Listener、Advice;
  • Spring Configuration、AOT/CGLIB 增强对象;
  • Jackson DTO、record、JPA Entity、序列化模型;
  • JNI/SWT/native 桥接类;
  • 由 Agent、ORM、Mock、热重载或自定义 ClassLoader 改写/重新定义的类;
  • 第三方框架和开源依赖;
  • 需要读取自身真实 class 字节码的类。

4. 不支持或受限的 JVM 能力

运行环境

  • 受保护应用必须使用随包 VLX JRE;
  • 不支持 JPMS -m 方式启动和单文件源码启动;
  • classpath 上的普通 JAR 必须由打包器登记,不能在部署时任意追加;
  • 不应使用 VLX JRE 运行未保护的普通应用。

调试和 Agent

  • 不支持 JVMTI、JDWP 调试器、性能分析器、覆盖率和多数 APM agent;
  • 不支持 -javaagent-agentlib、热重载和类重定义;
  • 需要字节码织入的处理应在编码前完成。

启动优化

  • 不支持 CDS、AppCDS 和 AOT;
  • ZGC 与 ShenandoahGC 不在 P4JX 运行时支持范围内。

5. 类资源和扫描器

读取保护类的 .class 资源时,获得的是元数据桩:保留类名、签名和注解,不含真实方法体。

  • 普通反射可读取元数据,但不能恢复原始字节码;
  • 自行解析物理 ZIP 的工具默认看不到 P4JX 内容,可尝试 --zip-overlay scanner
  • ClassGraph、Reflections 等 classpath 扫描器在 Spring Boot 中可能需要 --layout fat
  • ZipInputStream/JarInputStream 从内存或网络流解析 P4JX 不受支持;
  • zipfs 视图只读,不能修改归档。

6. 归档行为

  • .jar 后缀不代表普通 JAR;内容仍是 P4JX;
  • Multi-Release JAR 在编码时按目标 Java 版本展平;
  • 原 JAR 签名和证书语义不保留,需要时应对最终交付物做外部分发签名;
  • 不要修改、重压缩或合并生成的 P4JX 文件。