Java运行时如何从.jmod模块文件加载类
首先明确核心原因:.jmod 是JDK9为模块化系统设计的专属归档格式,和普通.jar的标准ZIP结构不兼容,有独立的文件索引、校验规则,这也是URLClassLoader无法直接读取jmod内容的根本原因。
可行实现方案
零内置依赖实现
JDK从9版本开始,运行时自带了专门处理jmod文件的工具类,位于com.sun.tools.jmod包下,不需要引入第三方包即可完成jmod内容解析。
实现逻辑:
- 用
JmodFile类直接打开目标jmod文件,获取内部所有文件条目的遍历能力 - 自定义类加载器重写
findClass方法:根据传入的类名,拼接成jmod内部类文件的标准路径(类名转为斜杠分隔路径,前缀补全classes/),从jmod条目流中读取对应类的字节码,再通过defineClass方法把字节码转换为可被JVM识别的Class对象
核心参考代码:
// 打开目标jmod文件 JmodFile jmodFile = new JmodFile(Paths.get("目标.jmod文件路径")); // 自定义类加载器 ClassLoader jmodLoader = new ClassLoader(Application.class.getClassLoader()) { @Override protected Class<?> findClass(String className) throws ClassNotFoundException { String entryPath = "classes/" + className.replace('.', '/') + ".class"; JmodFile.Entry targetEntry = jmodFile.stream() .filter(entry -> entry.path().equals(entryPath)) .findFirst() .orElseThrow(() -> new ClassNotFoundException(className)); byte[] classByteCode = jmodFile.readAllBytes(targetEntry); return defineClass(className, classByteCode, 0, classByteCode.length); } };
注意:调用内置jmod工具类时,需要在编译配置中将jdk.jmod模块加入编译路径,否则会出现类找不到的编译错误。
兼容适配方案
如果介意com.sun开头的内部API在不同JDK版本下的兼容差异,可以选用完全独立实现的jmod解析开源库。这类库内置了jmod格式的完整解析逻辑,不依赖JDK非公开接口,跨JDK版本兼容性更稳定。
IDE场景优化提示
做代码内容提示的场景,不需要走完整的类加载流程:
- 从jmod流中读取类字节码后,可直接用ASM等轻量字节码解析库提取类的结构信息(方法签名、字段、继承关系、注解内容),不需要真的把类加载到JVM内存中完成初始化。相比之前调用
javap命令的方案,整体性能会提升数倍 - 第一次解析完jmod的类结构后,可将索引结果存在本地缓存,IDE下次启动时直接读取缓存内容,不需要重复扫描大体积的jmod文件,进一步降低启动阶段的加载耗时
内容的提问来源于stack exchange,提问作者Omega UI
相关产品推荐
相关产品推荐

