接着昨天的记录,今天继续开始了。在JDK9中,由于Jigsaw项目引入了Java平台模块化系统(JPMS),Java SE的源代码被划分为一系列模块。类加载器,类文件容器等都发生了非常大的变化,API已经被划分到具体的模块中,所以上文中,利用“——Xbootclasspath/p” 替换某个Java核心类型代码,实际上变成了对对应的模块进行的修补,可以采用下面的解决方案:首先,确认要修改的类文件已经编译好,并按照对应模块结构存放,然后,给模块打补丁:
java --patch-module java.base=your_pathch yourApp
- 拓展类加载器将被重命名为平台类加载器(Platform Class-Loader),而且extension机制规则被移除。也就意味着,如果我们指定Java.ext.dirs环境变量,或者lib/ext目录存在,JVM将直接返回错误!建议解决方法就是将其放入classpath里。
- 部分不需要AllPermission的Java基础模块,被降级到平台类加载器中,相应的权限粒度也被更精细粒度地限制起来。
- rt.jar和tools.jar同样是被移除了!JDK的核心类库以及相关资源,被存储在jimage文件中,并通过新的JRT文件系统访问,二不是原有的JAR文件系统。虽然看起来很惊人,但幸好对于大部分软件的兼容性影响,其实是有限的,更直接的影响的是IDE等软件,通常只要升级到最新版本就可以了。
- 增加了Layer的抽象,JVM启动默认创建BootLayer,开发者也可以自己去定义和实例化Layer,可以更加方便的实现类似容器一般的逻辑抽象。结合了Layer,目前的JVM内部结构就变成了下面的层次,内建类加载器都在BootLayer中,其他Layer内部有自定义的类加载器,不同版本模块可以同时工作在不同的Layer。谈到类加载器,绕不够的一个话题是自定义类加载器,常见的场景有:
- 实现类似进程内隔离,类加载器实际上用做不同的命名空间,以提供类似容器、模块化的效果。例如,两个模块依赖于某个类库的不同版本,如果分别被不同的容器加载,就可以互不干扰。这个方面的集大成这是JavaEE和OSGI、JPMS等框架。
- 应用需要从不同的数据源获取类定义信息,例如网络数据源,而不是本地文件系统。
- 或者是需要自己操纵字节码,动态修改或者生成类型。我们可以总体上简单理解自定义类加载过程:
- 通过指定名称,找到其二进制实现,这里往往就是自定义类加载器会定制的部分,例如在特定数据源根据名字获取字节码,或者修改或者生成字节码。
- 然后,创建Class对象,并完成类加载过程。二进制信息到Class对象的转换,通常就依赖defineClass,我们无需自己实现,它是final方法。有了Class对象,后续完成加载过程就顺理成章了。