深入理解JVM(③)Java的模塊化


前言

JDK9引入的Java模塊化系統(Java Platform Module System ,JPMS)是 對Java技術的一次重要升級,除了像之前JAR包那樣充當代碼的容器之外,還包括:

  • 依賴其他模塊的列表。
  • 導出的包列表,即其他模塊可以使用的列表。
  • 開放的包列表,即其他模塊可反射訪問模塊的列表。
  • 使用的服務列表。
  • 提供服務的實現列表。

模塊化系統

可配置的封裝隔離機制解決了原來類路徑上跨文件的public類的可訪問性的問題。public類型不再意味着所有地方代碼都可以訪問它們,未導出未開放的類是不能夠被外部使用。

舉例說明:

新創建一個maven工程,並創建兩個module。

在這里插入圖片描述

在每個module的Language level 和 SDK 設置成JDK9

在這里插入圖片描述在這里插入圖片描述

然后在每個module的頂層目錄中創建module-info.java

在這里插入圖片描述

在ExampleOne中創建兩個不同package下的類,ExampleFirstExampleOne

package com.jimoer.jdkmoduleOne.test;

public class ExampleFirst {

    private int id;

    private String name;

    private String sex;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "ExampleFirst{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                '}';
    }
}
package com.jimoer.jdkmoduleOne;

public class ExampleOne {


    private int id;

    private String name;

    private String arg;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getArg() {
        return arg;
    }

    public void setArg(String arg) {
        this.arg = arg;
    }

    @Override
    public String toString() {
        return "ExampleOne{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", arg='" + arg + '\'' +
                '}';
    }
}

然后在ExampleOne的module-info.java中聲明導出包的路徑。

module exampleOne {

     // 導出包路徑
    exports com.jimoer.jdkmoduleOne.test;

}

在ExampleTwo中聲明requires為引入包

module exampleTwo {
    requires exampleOne;
}

然后在ExampleTwo中使用ExampleOne中的類

ublic class ExampleTwo {

    public static void main(String[] args) {

        ExampleFirst first = new ExampleFirst();

        first.setId(1);
        first.setName("余歡水");
        first.setSex("男");
        
        System.out.println(first);
    }
}

運行結果:

ExampleFirst{id=1, name='余歡水', sex='男'}

但是當在ExampleTwo中引用ExampleOne中非導出包下的類時就會編譯出錯。
在這里插入圖片描述
如上圖提示,所有不被導出的包默認都被封裝在模塊里面。

模塊的兼容性

為了使可配置的封裝隔離機制能夠兼容傳統的類路徑查找機制,JDK9提出了與“類路徑”(ClassPath)相對應的“模塊路徑”(ModulePath)的概念。只要放在類路徑上的JAR文件,都會被當作傳統的JAR包來對待;相應地,只要放在模塊路徑上的JAR文件,即使沒有使用JMOD后綴,甚至不包含module-info.class文件,也仍然會被當作一個模塊來對待。

為了保證Java應用升級到JDK9之后依然使用傳統的類路徑,不會受到影響,制定了三條規則來保證兼容性。

  • JAR文件在類路徑的訪問規則:所有類路徑下的JAR文件及其他資源文件,都被視為自動打包在一個匿名模塊(Unnamed Module)里,這個匿名模塊幾乎是沒有任何隔離的,它可以看到和使用類路徑上所有的包、JDK模塊中所有的導出包,以及模塊路徑是哪個所有模塊中導出的包。
  • 模塊在模塊路徑的訪問規則:模塊路徑下的具名模塊(Named Module)只能訪問到她依賴定義中列明依賴的模塊和包,匿名模塊里所有的內容對具名模塊來說都是不可見的,即具名模塊看不見傳統JAR包的內容。
  • JAR文件在模塊路徑的訪問規則:如果把一個傳統的、不包含模塊定義的JAR文件放置到模塊路徑中,它就會變成一個自動模塊(Automatic Module)。

模塊化下的類加載器

JDK9為了保證兼容性,依然保持了三層類加載器架構以及雙親委派模型。但是為了模塊化系統的順利實施,還是對類加載器做了一些改動。

  • 首先,擴展類加載器(Extension Class Loader)被平台類加載器(Platform Class Loader)取代。因為模塊化天然的支持擴展,自然不需要在存在擴展類加載器了。
  • 其次,平台類加載器和應用類加載器都不再派生自java.net.URLClassLoader,如果有程序直接依賴了這種繼承關系,或者依賴了URLClassLoader類特定方法,那代碼很可能會在JDK9及更高版本的JDK中崩潰。
  • 最后,JDK9中雖然仍然維持着三層類加載器和雙親委派架構,但類加載的委派關系也發生了變動。當平台及應用程序類加載器收到類加載請求,在委派給父加載器加載前,要先判斷該類是否能夠歸屬到某一個系統模塊中,如果可以找到這樣的歸屬關系,就要優先委派給負責哪個模塊的加載器完成加載,這可以算是對雙親委派的第四次破壞
    JDK9前后三層類加載器的架構圖對比如下:
    在這里插入圖片描述


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM