Java9 模块化

Posted by NotGeek on May 27, 2020

JAVA 9 的模块化

TOC

[TOC]

模块化前时代

  • Ant 时代(时代比较老)
  • Maven 时代(Gradle)
  • OSGI 时代 ( 没用过

Ant

javac 命令,Java 早就有了,

1
2
3
4
5
<!--... -->
<target>
    <delete dir="${file}"/>
</target>
<!--... -->

主要进行了文件操作。

Maven

  • 文件管理 <resource>
  • 版本管理 <dependency>GAV 帮我们确定一个版本。
    • dependencyManagement

缺点

  • 编译时进行处理的,运行时加载的一些类,

OSGI

  • http://enroute.osgi.org

运行时操作的

OSGI 并不比 模块化特别差。

Eclipse 就是基于 OSGI 来构建的。

Spring 也支持过 OSGI,动态模块化,OSGI 反而把问题搞复杂了,间接依赖很难去把控


加载的时候,文件系统不一定加载具体某个版本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
       
    +--------------+                     +--------------+
    |  ObjectUtils |                     |  StringUtils |
    +--------------+                     +--------------+ 
           |                                   |
           |                                   |
           +-----------------+-----------------+
                             |
    +------------------------+------------------------------+   文件系统
    |                        |                              |
    |        +--------------+----------+                   |
    |        |                          |                   |
    |   +------------------+      +------------------+      |
    |   | commons-lang 2.4 |      | commons-lang 2.6 |      |
    |   +------------------+      +------------------+      |
    |                                                       |
    +-------------------------------------------------------+
    

文件系统加载的不确定性,#list(File) 加载的不确定性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
                         +--------------+         
                         |    Tomcat    |         
                         +--------------+ 
                               |
                             Tomcat/lib
                               |
                         +---------------+         
                         |  ClassLoader  |
                         |    Commons    |       
                         +---------------+ 
                                |
            +-------------------+---------------------+
            |                                         |
      +-------------+                          +-------------+
      |    App1     |                          |   App1      |
      +-------------+                          +-------------+
           |                                           |
         WEB-INF/lib                                WEB-INF/lib
           |                                           |
      +---------------+                        +---------------+  
      | ClassLoader1  |                        | ClassLoader1  |   
      +---------------+                        +---------------+ 
           |                                          |
           |                                          |
      +---------------+                        +---------------+  
      | ClassLoader1  |                        | ClassLoader1  |   
      +---------------+                        +---------------+ 
      
      ~app1/WEB-INF/                           ~app1/WEB-INF/
      lib/commons-lang-2.4.jar                  lib/commons-lang-2.5.jar

Tomcat 有 自己的 Commons

我们启动程序有一个 -classpath 环境变量,会导致另一个事情,没有办法区分。


在本地环境可以,在线上部署的时候不可以的时候,

  • ClassLoader
  • Tomcat 有一个 WebAppClassLoader extends URLClassLoader

-classpath 里边的时候就是先来先服务,主要就是一位内 URLClassLoaderaddURL 方法。

URLClassLoader#findClass

  • 就是 getResource 的方法,先来先服务。通过类文件去寻找。
    • return defineClass(className)

如果可以清楚的知道我 jar 包的版本

  • NoSuchMethodException

模块化

  • 模块声明
    • module com.darian{}
    • 依赖
      • requires
    • 导出
      • exports
1
2
D:\anzhuanga\Java\jdk-11.0.1\bin\java.exe "-javaagent:D:\anzhuang\IntelliJ IDEA 2020.1\lib\idea_rt.jar=6529:D:\anzhuang\IntelliJ IDEA 2020.1\bin" -Dfile.encoding=UTF-8 -p D:\GitHub_Repositories\mercyblitz-gp-public\java9-modular-demo\out\production\java9-modular-demo -m com.darian/helloworld.com.darian.java9.helloWorld.HelloWorldMain
Hello, World

-m -p

- module-path 没有了 classpath,一直跟到了 module-info 路径下边,

问题

模块不是想要什么就有什么。

如果把 module 删了的化,还是想用啥用啥。

1
2
3
4
module com.darian {
    requires java.logging;
    requires java.management;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/***
 *
 *
 * @author <a href="mailto:[email protected]">Darian</a> 
 * @date 2020/5/28  9:16
 */
public class HelloWorldMain {
    public static void main(String[] args) {
        Logger logger = Logger.getLogger(HelloWorldMain.class.getName());
        logger.info("xxx");
        System.out.println("Hello, World");

        RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
        System.out.println(runtimeMXBean.getUptime());
    }
}

优点

  • 就是我们按需引入就好了

缺点

  • 就是我们不许知道在 类在哪里。

运行时,只需要运行我的 jar 包就更小了,就会容量变得更加的小。

  • 它还可以显示的帮我做隔离,

另一个目录下 可以引入另一个模块。

  • Java 的另一个程序支持,引入就可以

定义模块

  • 模块结构
  • 模块描述文件
    • - module-info.class
  • Java 平台模块

在 模块化里边,并没有了 public 的类。

必须显示的 exports ,支队本模块来 可读性


启动的时候,会更加的小。


Maven 的使用就发生了变化。

使用模块

  • 模块路径
  • 模块解析
  • 模块可读性
  • 模块访问性
  • 隐形可读性

变化

  • -module-path 取代了 class-path
1
2
3
4
5
module user.domain {
    exports com.darian.domain;
    // 不需要依赖其他模块
}

1
2
3
4
5
6
7
8
9
10
11
12
module user.service {

    // transitive 传递依赖
    requires transitive user.domain;
    requires java.logging;

    // 导出
    // 1. 本模块的 public class 需要显示的 exports
    // 2. exports 不支持子包传递
    exports com.darian.service;
    exports com.darian.service.impl;
}
1
2
3
4
module bootstrap {

    requires  user.service;
}

你可以传递依赖过来。

  • 传递依赖会特别麻烦。

  • 没有增加复杂度,只是增加了透明度。


高端玩家的游戏

JAVA 9 是 -claspath-module-path 混用。

工具整合

  • Maven
  • IDE
    • Idea

兼容性

  • 非命名模块
  • 自动模块
1
2
3
D:\anzhuanga\Java\jdk-11.0.1\bin\java.exe "-javaagent:D:\anzhuang\IntelliJ IDEA 2020.1\lib\idea_rt.jar=8021:D:\anzhuang\IntelliJ IDEA 2020.1\bin" -Dfile.encoding=UTF-8 -p D:\GitHub_Repositories\mercyblitz-gp-public\java9-module-demo\bootstrap\target\classes;D:\GitHub_Repositories\mercyblitz-gp-public\java9-module-demo\user-service\target\classes;D:\GitHub_Repositories\mercyblitz-gp-public\java9-module-demo\user\target\classes;

...

Java 9 以后通过,-p 引入

就是 module-pathclass-path 类似,

它即使可以帮你把这个东西搞进来,但是它还是无法预判你用到了哪些东西

你看不出来一个很明显的提升

https://openjdk.java.net/projects/jigsaw/spec/sotms

使用场景

  • 当你场景受限,需要直系依赖的时候就有用了。

Spring 的使用

  • spring.io 工程。
    • https://spring.io/projects/platform#learn
      • spring-io-platform 帮你做到了版本管理,
      • 而我们用模块化的时候,当工具做的更好的时候,可能使用的更加顺手