• Java虚拟机:Java模块化系统


    image.png

    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
    ......
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    OSGi – JPMS互操作性概念验证

    3、模块化的类加载

    为了保证兼容性,JDK 9并没有从根本上动摇从JDK 1.2以来运行了二十年之久的三层类加载器架构以及双亲委派模型。

    1)模块化下的类加载器变动

    模块化下的类加载器仍然发生了一些应该被注意到变动,主要包括以下几个方面:

    • 扩展类加载器(Extension Class Loader)被平台类加载器(Platform Class Loader)取代
    • 平台类加载器和应用程序类加载器都不再派生自java.net.URLClassLoader
    • 现在启动类加载器、平台类加载器、应用程序类加载器全都继承于jdk.internal.loader.BuiltinClassLoader
    image.png

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 平台类加载器负责加载的模块:
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 应用程序类加载器负责加载的模块:
    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*
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
  • 相关阅读:
    JTextArea 显示行号
    SpringBoot(二) - 核心配置文件
    JWT学习
    系统架构师备考倒计时23天(每日知识点)Redis篇
    【详细】Linux系统安装Python3
    计算机网络——数据链路层(滑动窗口协议: 选择重传)(点对点协议 PPP)
    Java锁的逻辑(结合对象头和ObjectMonitor)
    【计算机组成原理】读书笔记第二期:使用有棱有角的内存
    netdata邮件告警配置
    Android 实现GIF播放的几种方式
  • 原文地址:https://blog.csdn.net/qq_44895397/article/details/112974115