Java模块化系统目录
- 1、Java模块化系统
- 2、模块化的兼容性
- 1)模块路径
- 2)模块化系统访问路径规则
- 3)它本身面临的模块间的管理和兼容性问题
- 3、模块化的类加载器
- 1)模块化下的类加载器变动
- 2)类加载的委派关系变动
1、Java模块化系统
JDK9开始引入,目的:为了能够实现模块化的关键目标:可配置的封装隔离机制。
可配置的封装隔离机制主要解决:
- 首先要解决JDK9之前基于类路径(ClassPath)来查找依赖的可靠性问题;
- 还解决了原来类路径上跨JAR文件的public类型的可访问性问题。
JDK 9的模块不仅仅像之前的JAR包那样只是简单地充当代码的容器,除了代码外,Java的模块定义还包含以下内容:
- 依赖其他模块的列表。
- 导出的包列表,即其他模块可以使用的列表。
- 开放的包列表,即其他模块可反射访问模块的列表。
- 使用的服务列表。
- 提供服务的实现列表。
2、模块化的兼容性
1)模块路径
为了使可配置的封装隔离机制能够兼容传统的类路径查找机制,JDK 9提出了“模块路径”(ModulePath)的概念。
- 某个类库到底是模块还是传统的JAR包,只取决于它存放在哪种路径上。
- 只要是放在类路径上的JAR文件,无论其中是否包含模块化信息(是否包含了module-info.class文件),它都会被当作传统的JAR包来对待;
- 相应地,只要放在模块路径上的JAR文件,即使没有使JMOD后缀,甚至说其中并不包含module-info.class文件,它也仍然会被当作一个模块来对待。
2)模块化系统访问路径规则
模块化系统将按照以下规则来保证使用传统类路径依赖的Java程序可以不经修改地直接运行在 JDK 9及以后的Java版本上:
- 模块在模块路径的访问规则:模块路径下的具名模块(Named Module)只能访问到它依赖定义中列明依赖的模块和包,匿名模块里所有的内容对具名模块来说都是不可见的,即具名模块看不见传统JAR包的内容。
- JAR文件在类路径的访问规则:所有类路径下的JAR文件及其他资源文件,都被视为自动打包在一个匿名模块(Unnamed Module)里,这个匿名模块几乎是没有任何隔离的,它可以看到和使用类路径上所有的包、JDK系统模块中所有的导出包,以及模块路径上所有模块中导出的包。
- JAR文件在模块路径的访问规则:如果把一个传统的、不包含模块定义的JAR文件放置到模块路径中,它就会变成一个自动模块(Automatic Module)。尽管不包含module-info.class,但自动模块将默认依赖于整个模块路径中的所有模块,因此可以访问到所有模块导出的包,自动模块也默认导出自己所有的包。
3)它本身面临的模块间的管理和兼容性问题
- 如果同一个模块发行了多个不同的版本,那只能由开发者在编译打包时人工选择好正确版本的模块来保证依赖的正确性。
- Java模块化系统目前不支持在模块定义中加入版本号来管理和约束依赖,本身也不支持多版本号的概念和版本选择功能。
- 我们不论是在Java命令、Java类库的API抑或是《Java 虚拟机规范》定义的Class文件格式里都能轻易地找到证据,表明模块版本应是编译、加载、运行期间都可以使用的。譬如输入
java --list-modules
,会得到明确带着版本号的模块列表:
java.base@13.0.2
java.compiler@13.0.2
java.datatransfer@13.0.2
java.desktop@13.0.2
java.instrument@13.0.2
java.logging@13.0.2
java.management@13.0.2
java.management.rmi@13.0.2
java.naming@13.0.2
java.net.http@13.0.2
......
OSGi – JPMS互操作性概念验证
3、模块化的类加载器
为了保证兼容性,JDK 9并没有从根本上动摇从JDK 1.2以来运行了二十年之久的三层类加载器架构以及双亲委派模型。
1)模块化下的类加载器变动
模块化下的类加载器仍然发生了一些应该被注意到变动,主要包括以下几个方面:
- 扩展类加载器(Extension Class Loader)被平台类加载器(Platform Class Loader)取代
- 平台类加载器和应用程序类加载器都不再派生自
java.net.URLClassLoader
- 现在启动类加载器、平台类加载器、应用程序类加载器全都继承于
jdk.internal.loader.BuiltinClassLoader
2)类加载的委派关系变动
JDK9中虽然仍然维持着三层类加载器和双亲委派的架构,但类加载的委派关系也发生了变动。
当平台及应用程序类加载器收到类加载请求,在委派给父加载器加载前,要先判断该类是否能够归属到某一个系统模块中,如果可以找到这样的归属关系,就要优先委派给负责那个模块的加载器完成加载,也许这可以算是对双亲委派的第四次破坏。
### 3)三个类加载器归属关系
在Java模块化系统明确规定了三个类加载器负责各自加载的模块,即前面所说的归属关系
- 启动类加载器负责加载的模块:
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.unsupported jdk.sctp
- 平台类加载器负责加载的模块:
java.activation* java.compiler*
java.scripting java.se
java.se.ee java.corba*
java.security.jgss java.smartcardio
java.sql.rowset java.xml.bind*
java.xml.crypto java.xml.ws*
java.xml.ws.annotation* java.transaction*
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 java.sql
- 应用程序类加载器负责加载的模块:
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*