嘘~ 正在从服务器偷取页面 . . .

java模块化系统


Java模块化系统

Java模块化系统(Java Platform Module System,JPMS)是在JDK 9中引入的。

1、封装隔离机制

主要是为了实现可配置的封装隔离机制。

Java虚拟机对类加载架构也做出了相应的变动调整,才使模块化系统得以顺利地运作。

JDK 9的模块不仅仅像之前的JAR包那样只是简单地充当代码的容器,除了代码外,Java的模块定义还包含以下内容:

(1)依赖其他模块的列表。

(2)导出的包列表,即其他模块可以使用的列表。

(3)开放的包列表,即其他模块可反射访问模块的列表。

(4)使用的服务列表。

(5)提供服务的实现列表。

可配置的封装隔离机制作用:

(1)解决JDK 9之前基于类路径(ClassPath)来查找依赖的可靠性问题。

在JDK 9之前前,如果类路径中缺失了运行时依赖的类型,那就只能等程序运行到发生该类型的加载、链接时才会报出运行的异常。

在JDK 9以后,如果启用了模块化进行封装,模块就可以声明对其他模块的显式依赖,Java虚拟机就能够在启动时验证应用程序开发阶段设定好的依赖关系在运行期是否完备,如有缺失那就直接启动失败,从而避免了大部分由于类型依赖而引发的运行时异常。

(2)解决原来类路径上跨JAR文件的public类型的可访问性问题。

JDK 9中的public类型不再意味着程序的所有地方的代码都可以随意访问到它们,模块提供了更精细的可访问性控制,必须明确声明其中哪一些public的类型可以被其他哪一些模块访问,这种访问控制也主要是在类加载过程中完成的。

2、模块的兼容性

(一)向下兼容

为了实现可配置的封装隔离机制能够兼容传统的类路径查找机制,JDK 9提出了与“类路径”(ClassPath)相对应的“模块路径”(ModulePath)的概念。

就是一个类库到底是模块还是传统的JAR包,只取决于它存放在哪种路径上。

只要放在类路径上的JAR文件,无论其中是否包含模块化信息(是否包含了module-info.class文件),它都会被当作传统的JAR包来对待;

只要放在模块路径上的JAR文件,即使没有使用JMOD后缀,甚至说其中并不包含module-info.class文件,它也仍然会被当作一个模块来对待。

传统类路径依赖的Java程序可以不经修改地直接运行在JDK 9及以后的Java版本上,模块化系统提供的运行规则:

(1)JAR文件在类路径的访问规则。

所有类路径下的JAR文件及其他资源文件,都被视为自动打包在一个匿名模块(Unnamed Module)里,这个匿名模块几乎是没有任何隔离的,它可以看到和使用类路径上所有的包、JDK系统模块中所有的导出包,以及模块路径上所有模块中导出的包。

(2)模块在模块路径的访问规则

模块路径下的具名模块(Named Module)只能访问到它依赖定义中列明依赖的模块和包,匿名模块里所有的内容对具名模块来说都是不可见的,即具名模块看不见传统JAR包的内容。

(3)JAR文件在模块路径的访问规则

如果把一个传统的、不包含模块定义的JAR文件放置到模块路径中,它就会变成一个自动模块(Automatic Module)。尽管不包含module-info.class,但自动模块将默认依赖于整个模块路径中的所有模块,因此可以访问到所有模块导出的包,自动模块也默认导出自己所有的包。

这3条规则保证了即使Java应用依然使用传统的类路径,升级到JDK 9对应用来说几乎不会有任何感觉,项目也不需要专门为了升级JDK版本而去把传统JAR包升级成模块。

(二)模块直接的兼容

模块间的管理和兼容性问题:

当同一个模块发行了多个不同的版本,那只能由开发者在编译打包时人工选择好正确版本的模块来保证依赖的正确性。

暂不支持在模块定义中加入版本号来管理和约束依赖,本身也不支持多版本号的概念和版本选择功能。

但是查看模块列表(java--list-modules)时可以看到版本信息。

编译时使用“javac–module-version”可以用来指定模块版本。

java.lang.module.ModuleDescriptor.Version接口可以在运行时获取到模块的版本号。

3、模块化下的类加载器

为了保证兼容性,JDK 9类加载依旧使用三层类加载器架构以及双亲委派模型。

(一)模块类加载器变动

但模块化下的类加载器有变化:

(1)扩展类加载器(Extension Class Loader)被平台类加载器(Platform ClassLoader)取代。

取消 <JAVA_HOME>\lib\ext目录、<JAVA_HOME>\jre目录,可以借助模块以组合构建出程序运行所需的JRE,如只使用java.base模块中的类型,可以构建需要的包:

jlink -p $JAVA_HOME/jmods --add-modules java.base --output jre

(2)平台类加载器和应用程序类加载器都不再派生自java.net.URLClassLoader。

现在启动类加载器、平台类加载器、应用程序类加载器全都继承于jdk.internal.loader.BuiltinClassLoader,在BuiltinClassLoader中实现了新的模块化架构下类如何从模块中加载的逻辑,以及模块中资源可访问性的处理。

如果有程序直接依赖了这种继承关系,或者依赖了URLClassLoader类的特定方法,那代码很可能会在JDK9及更高版本的JDK中崩溃。

JDK9之前的类加载器继承结构

JDK9之后的类加载器继承结构

(3)JDK 9中类加载的委派关系也发生了变动。

当平台及应用程序类加载器收到类加载请求,在委派给父加载器加载前,要先判断该类是否能够归属到某一个系统模块中,如果可以找到这样的归属关系,就要优先委派给负责那个模块的加载器完成加载,也许这可以算是对双亲委派的第四次破坏。

JDK9后的类加载器委派关系

(二)类加载器负责模块

三个类加载器负责各自加载的模块:

(a)启动类加载器负责加载的模块:

java.base                        java.security.sasl
java.datatransfer                java.xml
java.desktop                     jdk.httpserver
java.instrument                  jdk.internal.vm.ci
java.logging                     jdk.management
java.management                  jdk.management.agent
java.management.rmi              jdk.naming.rmi
java.naming                      jdk.net
java.prefs                       jdk.sctp
java.rmi                         jdk.unsupported

(b)平台类加载器负责加载的模块:

java.activation*                jdk.accessibility
java.compiler*                  jdk.charsets
java.corba*                     jdk.crypto.cryptoki
java.scripting                  jdk.crypto.ec
java.se                         jdk.dynalink
java.se.ee                      jdk.incubator.httpclient
java.security.jgss              jdk.internal.vm.compiler*
java.smartcardio                jdk.jsobject
java.sql                        jdk.localedata
java.sql.rowset                 jdk.naming.dns
java.transaction*               jdk.scripting.nashorn
java.xml.bind*                  jdk.security.auth
java.xml.crypto                 jdk.security.jgss
java.xml.ws*                    jdk.xml.dom
java.xml.ws.annotation*         jdk.zipfs

(c)应用程序类加载器负责加载的模块:

jdk.aot                         jdk.jdeps
jdk.attach                      jdk.jdi
jdk.compiler                    jdk.jdwp.agent
jdk.editpad                     jdk.jlink
jdk.hotspot.agent               jdk.jshell
jdk.internal.ed                 jdk.jstatd
jdk.internal.jvmstat            jdk.pack
jdk.internal.le                 jdk.policytool
jdk.internal.opt                jdk.rmic
jdk.jartool                     jdk.scripting.nashorn.shell
jdk.javadoc                     jdk.xml.bind*
jdk.jcmd                        jdk.xml.ws*
jdk.jconsole


版权声明: 本博客所有文章除特別声明外,均采用 CC BY-SA 4.0 许可协议。转载请注明来源 Small-Rose / 张小菜 !
评论
  目录