1.Why
在Java Bug System中,我们可以看到Java9与ClassLoader相关的一系列issue:
JDK-8170294:java.lang: Define behaviour of
null
resource 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
ClassLoader
with respect to loading array classesJDK-8165563:java.lang: Update
ClassLoader.getSystemClassLoader()
JDK-7180225:java.lang: Declare
SecurityException
consistently 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.参考
|
|