JDK 9 的 PlatformClassLoader 只是简单改个名吗?
都知道JDK9之后将扩展类加载器(ExtensionClassLoader)重命名为平台类加载器(PlatformClassLoader),难道只是简单的重命名吗?都有什么变化?
带来的变化
1.双亲委派模型的改变
JDK8:双亲委派是严格的“向上查找”:自定义——>App——>Ext——>Boot
JDK9+:为了适配模块化,当类加载器收到加载请求时,会先判断该类是否属于某个具体的模块
如果该类已经归属于某个模块,Java 会直接将请求委派给负责该模块的类加载器,而不再一层层往上托举
什么?谁判断的该类是否属于某个具体的模块?is引入的BuiltinClassLoader判断的
package jdk.internal.loader; protected Class<?> loadClassOrNull(String cn, boolean resolve) { synchronized (getClassLoadingLock(cn)) { // 检查这个类是否已经被加载过 Class<?> c = findLoadedClass(cn); if (c == null) { // 查找它属于哪个模块 LoadedModule loadedModule = findLoadedModule(cn); // --------- 情况 A:属于某个模块(走直达) ----------- //查到了,属于某个模块 if (loadedModule != null) { //获取这个模块的类加载器 BuiltinClassLoader loader = loadedModule.loader(); //如果是我自己 if (loader == this) { //模块系统初始化完成后,由我自己去加载 if (VM.isModuleSystemInited()) { c = findClassInModuleOrNull(loadedModule, cn); } } else { //甩给对应的加载器,实现“直达” c = loader.loadClassOrNull(cn); } } else { //--------- 情况 B:不属于任何已知模块(走传统双亲委派) ----------- //向上委派 if (parent != null) { c = parent.loadClassOrNull(cn); } // 向下退回 if (c == null && hasClassPath() && VM.isModuleSystemInited()) { c = findClassOnClassPathOrNull(cn); } } } if (resolve && c != null) resolveClass(c); return c; } }什么是模块化?
JDK9之前,只有包和Jar包,
问题一:只要一个jar包在ClassPath里,它里面所有的public类都能被任意访问,但我的public只想当前组件内部用,不暴露给外部
问题二:如果运行时两个jar包里有同名同包的类,先扫描的会覆盖后面的,会报错(如NoSuchMethodError)。
模块化系统,在包之上加了层:模块
一个模块不仅包含代码,还包含核心描述文件module-info.java:
- 我导出了什么(exports): 只有被导出的包,别的模块才能访问。
- 我依赖了什么(requires): 明确声明我需要哪些模块才能运行。
2.启动类加载器的改变
脱离了 C++ 的“隐形”实现:在过去,Bootstrap ClassLoader 完全由 C++ 实现,在 JDK 9 之后引入了BuiltinClassLoader的 Java 类。现在,Bootstrap、Platform 和 App 加载器全都继承自BuiltinClassLoader。
不再加载所有核心库:过去所有的 Java 核心类都由 Bootstrap 一把抓。现在,核心类被拆分成了不同的模块,Bootstrap 只负责加载最核心的模块(如java.base),而java.sql(数据库相关)、java.xml等模块,则交给了平台类加载器去加载。
3.目录结构与打包文件消失
rt.jar和tools.jar消失了,所有内置类被重新打包成模块,存在了lib/modules
4.类加载器微调
内置的三个加载器都改为了BuiltinClassLoader的子类
好处:
- 运行时性能与启动速度的飞跃,省去了沿途无效的逐级托举和全盘文件扫描
- 强封装性,阻止访问核心库内部的私有实现,
- 配置更可靠,项目依赖A.jar A.jar依赖B.jar,运行时不报错,但是执行A.jar里的某行代码,要加载B.jar里的类时,就会抛
ClassNotFoundException或NoClassDefFoundError现在:模块化要求在module-info.java中明确声明requires哪些模块。
package java.lang.module; public Builder requires(Requires req) { if (automatic) throw new IllegalStateException("Automatic modules cannot declare" + " dependences"); String mn = req.name(); if (name.equals(mn)) throw new IllegalArgumentException("Dependence on self"); if (requires.containsKey(mn)) throw new IllegalStateException("Dependence upon " + mn + " already declared"); requires.put(mn, req); return this; }- jlink自动裁剪,用什么裁什么
