兼容性与保护范围
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. 通常不应保护的类
- 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 文件。