JDK9-初尝模块化

Posted 58招聘技术团队

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDK9-初尝模块化相关的知识,希望对你有一定的参考价值。


        2017.9.21,JDK9 正式发布。对比JDK9以前,JDK9带来了许多的特性,这些特性有:模块化系统、JShel、集合工程方法、接口中的私有方法、HTTP2客户端等。这篇文章主要介绍JDK9中的模块系统。


一、JDK9 模块化系统 - Jigsaw


        Java 9起初的代号就叫Jigsaw,后来被更改为Modularity,Modularity提供了类似于OSGI框架的功能,模块之间存在相互的依赖关系,可以导出一个公共的API,并且隐藏实现的细节。为了更好的理解JDK9模块话,我们先看看JDK9以及JDK8的modular runtime images,也就是JDK和JRE。

    

        在jdk 9 以前,我们安装的JDK包目录结构如下:

 

JDK9-初尝模块化

        对于JDK目录结构的组成这里就不做太多的介绍了,这里主要关注一下这三个jar包:JDK_Home/lib/tools.jar,JDK_Home/lib/dt.jar,JDK_Home/jre/lib/rt.jar。


        其中tools.jar是系统用来编译类的时候用到的(例如javac的时候),tools.jar在JDK8中大约是18M。


        dt.jar 是运行环境类库,主要包含的是Swing包,dt.jar在JDK8中大约是160K。


        rt.jar包含了运行时的java类和资源文件,许多工具都依赖于rt.jar文件的位置。rt.jar在JDK8中大约是63M。在JDK9以前,我们的大部分程序在运行之前都需要将该jar加载至内存。

 

        再来看看JDK9的目录结构:

 

JDK9-初尝模块化


        在JDK9目录结构中我们看到,jre目录以及被移除掉了,同时增加了jmods、include和legal目录。我们重点关注的是jmods目录,在jmods目录中存储的是JMOD格式的平台模块,目前包含了99个模块。

 

        上面提及的三个JAR包,在JDK9中都被移除了。其中rt.jar被划分成了许多更小的模块被放进了jmods中,而dt.jar和tools.jar的功能都被jdk 9 中的bootstrap取代了


        JDK9中模块就是代码和数据的封装体,代码是指一些包括类型的Packages。Package是一些类路径名字的约定,而模块是一个或多个Packages组成的一个封装体,在JDK9 中,模块的是通过module-info.java来进行定义的。


二、创建第一个模块


        1.模块化:


        JDK9中的模块就是代码和数据的封装体,即模块是有一个或多个jar组成的一个封装体.在JDK9 中,模块的是通过module-info.java来进行定义的。

 

        接下来将利用Idea开始创建第一个JAVA的模块。


        目前IDEA 从2017.1 开始已经支持JDK9 的相关操作了。由于我们在平时的项目中基本上用的是MAVEN来进行管理,这里需要注意maven插件编译的版本至少需要3.6.1以上:

 

JDK9-初尝模块化


        2.开始创建第一个模块:


        这个模块中只有一个HelloWorld类:

 

JDK9-初尝模块化


        接着在根目录创建module-info.java 文件:

 

JDK9-初尝模块化


        创建之后我们会发现HelloWorld中开始报错,并提示org.slf4j没有在module中被读取:


JDK9-初尝模块化

        

        这就需要我们在modeule-info.java 中引入slf4j.api即可:

 

JDK9-初尝模块化


        3.更多的模块


        这样我们的第一个模块程序就能正确的运行了。接下来我们会创建更多的模块,用来看看模块之间的联系。


        首先我们创建第二个模块:jdk9.example.two:


JDK9-初尝模块化


        模块二中包含了一个SayHelloService接口和一个Person对象,分别为:

 

JDK9-初尝模块化

JDK9-初尝模块化


        第三个模块:jdk9.example.three。


        在第三个模块中只有SayHelloService的一个实现类:


JDK9-初尝模块化


        接下来我们通过这三个module 来进一步深入了解如何使用JDK9 中的module系统. 


        3.module-info.java


        这里先介绍一下module-info.java。module-info.java 是用来对模块进行管理的一个文件,文件存储在该模块的源文件层次结构的根目录下。通过这个文件可以来描述模块的名字、运行需要的模块以及堆外可见的包。


        在modeule-info.java文件中有5个模块描述符关键字:requires、exports、opens、provides、uses。

 

        Requires


        对于requires 语句 在第一个模块中已经有使用过了,它的作用是用于指定一个模块对另一个模块的依赖。 如果模块读取另一个模块,则第一个模块在其声明中需要有一个require语句。


        在JDK9中,java.base模块是原始模块,它不依赖于其他任何模块,在java.base模块中导出了java的核心软件包,例如java.lang,java.io等,目前每个模块都隐式读取java.base模块,所以我们在使用JDK的功能时,并不需要主动声明这些需要使用的模块

 

        exports 


        exports语句用于将模块中指定的包导出到所有模块,或者编译时或者运行时的模块列表,它有两种形式:

        exports <package>;

        exports <package> to <module1>, <module2>...;

 

        例如:


    module jdk9.example.two{

    exports service;

    exports model to jdk9.example.one;

    }

 

        上面指定了jdk9.example.two模块中将model模块导出到jdk9.example.one模块,也就是说只有jdkexampleone模块能够使用model包;而service包则导出给所有模块使用。


        在这里,public 关键字不再意味着任意的可访问性。访问的范围局限在JAR,想要访问 JAR包外的其他类,必须export。 任何模块之间的交互必须通过module-info文件来定义。

 

        opens


        opens开放语句允许对所有模块的反射访问指定的包或运行时指定的模块列表。 其他模块可以使用反射访问指定包中的所有类型以及这些类型的所有成员(私有和公共)。


        使用方法:

        opens <package>;

        opens <package> to <module1>, <module2>...;


        opens与exports都是将模块进行导出,但是区别在于使用opens可以通过反射来获取到指定包中所有的类型和类型成员(不管是私有还是公有成员);exports则是仅允许通过反射来获取到指定包中所有的公有(publish)类型和公有成员,即使在这些成员上使用了setAccessible(true)方法,公共类型的非公开成员也无法使用反射。

 

        看一个通过反射来获取Person的示例:

        在 jdk9.example.two 中 使用exports导出Person:

     

   module jdk9.example.two{

    exports service;

    exports model to jdk9.example.one;

    }

     

        在jdk9.example.one 中新建一个Reflect类:

 

JDK9-初尝模块化    

        运行结果 :

 

JDK9-初尝模块化


        从Person中成员定义可以看到,通过反射只能拿到publish的成员值。

     

        我们使用opens关键字:

     

    module jdk9.example.two{

    exports service;

    opens model to jdk9.example.one;

    }

        

        输出结果如下:

 

JDK9-初尝模块化


        使用了opens关键字后Person中的成员变量都能通过反射获取到其对应的值。

     

        这里我们可以意识到JDK9在尝试的提高代码的安全性,同时为了兼容以前的框架版本,开放出了不同的权限的关键字。

 

        provides 和uses


        JDK 9允许使用服务提供者和服务使用者分离的服务提供者机制。


        使用方法:

        provides <service_name> with <service_name_implementation>

        uses <service_type>


        示例:

        我们通过jdk9.example.one来调用jdk9.example.two中的SayHello接口,其中 jdk9.example.three中实现了该接口。

     

    jdk9.example.two导出接口包:

    module jdk9.example.two{

    exports service;

    uses SayHelloService;

    }

 

    jdk9.example.three 实现接口包:

    module jdk9.example.three{

    requires jdk9.example.two;

    provides SayHelloServie with SayHelloServieImpl;

    }

     

    

        在jdk9.example.one 中调用该接口:

           module jdk9.example.one {

        requires jdk9.example.three;

        requires jdk9.example.two;

        }

 

        

        打印结果:example three say hello;


三、Maven与Module


        看完上面的介绍会不会有这样的疑问:maven与module的关系是什么?


        在项目中,Maven主要负责项目依赖管理和项目的构建,而Module则是系统内置的用途表述组件之间的关系,管理的是一种强制的依赖关系,对于版本的管理还是需要maven这样的工具来进行。


四、结论


        总结一下JDK9模块化的好处:


        1、分离了JDK、JRE作为更小的模块,这样能减少JAVA程序运行的空间,使得java SE程序更加容易轻量部署。


        2、增强了系统的封闭性,对于没有导出的类,即使定义的是public也将不会被其它模块的类所引用到。这样我们可以隐藏那些不想暴露的内部细节,增强安全性。


        3、组件间的松耦合变得非常容易。

 

        对于 JAVA 9模块感兴趣的可以去读一读 《JAVA 9 Modularity Revealed》, 看完这本书会对 JDK9 模型具有更深入的了解。

 

参考网址:

https://blog.jetbrains.com/idea/2017/03/support-for-java-9-modules-in-intellij-idea-2017-1/

http://blog.csdn.net/u014042066/article/details/78122593

http://www.cnblogs.com/IcanFixIt/p/6947763.html



以上是关于JDK9-初尝模块化的主要内容,如果未能解决你的问题,请参考以下文章

JDK9-模块化系统

JDK9模块化知识和规则入门

初尝seajs,只提供自己学习做笔记

JDK9新特性

JDK9的新特性

SPI + JDK 9 + 模块信息.java