1.Why
在Java Bug System中,我们可以看到Java9与ClassLoader相关的一系列issue:
JDK-8170294:java.lang: Define behaviour of
nullresource nameJDK-8161230:java.lang: Add
ClassLoader.resources()JDK-8165346:java.lang: Specify exceptional condition for
get*Package()JDK-8165793:java.lang: Add
ClassLoader.isRegisteredAsParallelCapable()JDK-6516909:java.lang: Enhanced
ClassLoaderwith respect to loading array classesJDK-8165563:java.lang: Update
ClassLoader.getSystemClassLoader()JDK-7180225:java.lang: Declare
SecurityExceptionconsistently in class loader methodsJDK-8155770:Networking: Document support of
jar:scheme URLs inURLClassLoader
这些Issue表明了两个信息:
- 变化:在Java9,JVM的类加载机制发生了变化。
- 变化不大:JVM类加载机制的变化不大。如果有较大的变化,就不会只通过几个issue来实施,应该通过JEP来落地。
进一步思考一下,不难理解为什么JVM会出现类加载机制的变化?:
以Ext ClassLoader为例:
在Java9之前,JDK为了具有扩展性,会将扩展的jar包放到<JAVA_HOME>\lib\ext和java.ext.dirts下,Ext ClassLoader负责加载这些扩展包。
而从Java9开始,Java9引入了JPMS(Java Platform Module System),模块化机制帮助Java类库天然地具备扩展性。
因此,原来的扩展机制可以废弃掉,用来加载这些路径类库的类加载器——Ext ClassLoader也就完成了它的历史使命。
说明:Java9中,基于JPMS机制,tools.jar、rt.jar从物理层面上被拆分成了10+个jmod文件。
至于,类加载机制的变化不大,说明Java9不会因为JPMS而推翻JVM原有的双亲委派模型和类加载机制,只是为了在引入JPMS的同时,保证Java9的前向兼容性。

2.变化点1:新的双亲委派模型
在《【类加载机制】-1-类加载器剖析-类加载器速览》中,笔者对Java8的双亲委派模型评价为"妈宝模型"。
即,任何一个待加载的类,都要从Application ClassLoader一路向上,问上级类加载器能否加载。
在Java9,因为有了JPMS机制,任何一个类一定都有归属的module。
如果事先就定义好系统级的类加载器能够加载哪些系统级的module,那么这些module下的类就不必在加载的时候,都要走一圈向上级类加载器询问能否加载的过程了。
新的双亲委派模型,本质上就是在原有的双亲委派模型的基础上,给各种类加载器约定了责任田——即,谁的孩子谁直接带走。
下图对比了Java9前后的双亲委派模型差异。
比如:已知类A归属于系统moduleB,JVM已经约定系统moduleB由BootStrap ClassLoader加载,
因此,当加载类A时,如下图蓝色线,类A直接交给BootStrap ClassLoader加载。

附:Java9中各个类加载器默认加载的module
摘自《深入理解JVM》,周志明
- BootStrap ClassLoader负责加载的模块:
java.base
java.datatransfer
java.desktop
java.instrument
java.logging
java.management
java.management.rmi
java.naming
java.prefs
java.rmi
java.security.sasl
java.xml
jdk.httpserver
jdk.internal.vm.ci
jdk.management
jdk.management.agent
jdk.naming.rmi
jdk.net
jdk.sctp
jdk.unsupported
- Platform ClassLoader负责的
module
java.activation*
java.compiler*
java.corba*
java.scripting
java.se
java.se.ee
java.security.jgss
java.smartcardio
java.sql
java.sql.rowset
java.transaction*
java.xml.bind*
java.xml.crypto
java.xml.ws*
java.xml.ws.annotation*
jdk.accessibility
jdk.charsets
jdk.crypto.cryptoki
jdk.crypto.ec
jdk.dynalink
jdk.incubator.httpclient
jdk.internal.vm.compiler*
jdk.jsobject
jdk.localedata
jdk.naming.dns
jdk.scripting.nashorn
jdk.security.auth
jdk.security.jgss
jdk.xml.dom
jdk.zipfs
- App ClassLoader负责加载的
module
jdk.aot
jdk.attach
jdk.compiler
jdk.editpad
jdk.hotspot.agent
jdk.internal.ed
jdk.internal.jvmstat
jdk.internal.le
jdk.internal.opt
jdk.jartool
jdk.javadoc
jdk.jcmd
jdk.jconsole
jdk.jdeps
jdk.jdi
jdk.jdwp.agent
jdk.jlink
jdk.jshell
jdk.jstatd
jdk.pack
jdk.policytool
jdk.rmic
jdk.scripting.nashorn.shell
jdk.xml.bind*
jdk.xml.ws*
3.变化点2:ClassLoader的类层次关系
- 在Java9之前,JDK没有提供
BootStrapClassLoader类,ExtClassLoader类和AppClassLoader类继承于URLClassLoader。 - 在Java9之后,JDK提供了
BootClassLoader类,同时BootClassLoader、PlatformClassLoader、AppClassLoader类继承于BuiltinClassLoader。

查看Java9的BuiltinClassLoader::loadClass()方法源码:
| |
可以看到:JVM优先从module中查找是否加载了待加载的类:
| |
当待加载类不归属于系统级module,则还是沿用原来的双亲委派模型去加载:
| |
4.参考
| |