掌握Java9模塊化系統-基礎部分

模塊基礎

module是用來組織packages,經過模塊名稱(module’s name)來隔離不一樣模塊之間包的可讀性。所以是在Java的訪問限制機制public/private/protected上加了一層,先有模塊的可讀性纔有訪問性可言。同時jlink工具提供了提取程序最小運行時的支持。
java

模塊化機制給Java語言帶來一些新的關鍵字以下:bash


聰明的你可能會想起:在一個成熟的系統引入新的關鍵字,會不會對已有代碼命名形成衝突。答案是:不會。由於這些關鍵字的使用限定在模塊定義文件module-info.java,你在正常的Java代碼中仍是可使用這些關鍵字做爲標示符。

下面先稍微簡單介紹下上面關鍵字的做用:ide

exportsrequires是一對兒,前者用於導出模塊的某些包,後者則是導入須要引入的外部模塊的包。模塊化

provides/uses/with則是服務提供者機制下的用到的關鍵字,這個後文有講解。工具

transitive顧名思義就是指的可傳遞性,主要用於多個模塊串行依賴用於簡化書寫requires語句的。ui

to主要是和exports組合,用於將模塊的包導出到特定模塊,成爲其專屬女傭。this

open/opens主要是用於將模塊開放給其餘全部模塊,可是要注意編譯期和運行期的區別。其具體機制後門也會詳述。idea

好了,模塊的基本概念就到這裏了。聰明的你更指望的是一個能運行的實例吧,那咱們下面就開始從代碼的角度去使用咱們的模塊化機制咯。spa

簡單的模塊示例

下面咱們將定義三個模塊,這裏仍是沿用商品和訂單的栗子。咱們定義的三個模塊組織以下:命令行


這裏咱們定義三個模塊:goods/order/pojo,其依賴關係以下:

goods->order->pojo

接下來咱們依次創建好代碼目錄和 Java文件。固然你也能夠手動建立這些目錄和代碼。

pojo模塊

咱們先定義兩個實體類Goods.java和Order.java:

package pojo;

import java.util.List;

public class Goods {
    private String goodsName;
    private double price;
    private List<Order> orderList;

    public String getGoodsName() {
        return goodsName;
    }

    public void setGoodsName(String goodsName) {
        this.goodsName = goodsName;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public List<Order> getOrderList() {
        return orderList;
    }

    public void setOrderList(List<Order> orderList) {
        this.orderList = orderList;
    }

    @Override
    public String toString() {
        return "Goods{" +
                "goodsName='" + goodsName + '\'' +
                ", orderList=" + orderList +
                '}';
    }
}

package pojo;

import java.time.LocalDateTime;

public class Order {
    private LocalDateTime createTime;
    private LocalDateTime finishTime;
    private String orderName;
    private String orderUser;

    public Order(String orderName) {
        this.orderName = orderName;
        this.createTime = LocalDateTime.now();
        this.finishTime = LocalDateTime.now().plusDays(2);
        this.orderUser = "gxf";
    }

    public LocalDateTime getCreateTime() {
        return createTime;
    }

    public void setCreateTime(LocalDateTime createTime) {
        this.createTime = createTime;
    }

    public LocalDateTime getFinishTime() {
        return finishTime;
    }

    public void setFinishTime(LocalDateTime finishTime) {
        this.finishTime = finishTime;
    }

    public String getOrderName() {
        return orderName;
    }

    public void setOrderName(String orderName) {
        this.orderName = orderName;
    }

    public String getOrderUser() {
        return orderUser;
    }

    public void setOrderUser(String orderUser) {
        this.orderUser = orderUser;
    }

    @Override
    public String toString() {
        return "Order{" +
                "createTime=" + createTime +
                ", finishTime=" + finishTime +
                ", orderUser='" + orderUser + '\'' +
                '}';
    }
}複製代碼

接下來在模塊的根目錄建立module-info.java(注意模塊聲明文件必須在模塊源代碼文件的根目錄):

module pojo {
    exports pojo;
}複製代碼

至此咱們定義了名爲pojo的模塊,而且導出pojo這個包以供其餘模塊使用。

order模塊

這裏咱們定義一個OrderService類提供商品訂單查詢方法,其代碼以下:

package order;

import pojo.Order;

import java.util.List;

public class OrderService {
    public List<Order> queryOrdersByGoodsName(String goodsName) {
        return List.of(new Order("oder1"),new Order("oder2")
                ,new Order("oder3"),new Order("oder4"),new Order("oder5"));
    }
}
複製代碼

queryOrdersByGoodsName方法構造訂單對象列表,注意這裏使用Java10集合新的工廠方法來生成的List。

order模塊依賴pojo模塊,所以其module-info.java定義以下:

module order{
    exports order;
    requires pojo;
}複製代碼

咱們看到該模塊依賴pojo同時導出order包,覺得下面的goods模塊依賴order。

goods模塊

該模塊定義GoodsService類,用於查詢商品信息,其代碼以下:

package goods;


import order.OrderService;
import pojo.Goods;

public class GoodsService {

    private OrderService orderService = new OrderService();

    Goods queryGoodsInfoByName(String goodsName) {
        Goods goods = new Goods();
        goods.setGoodsName(goodsName);
        goods.setOrderList(orderService.queryOrdersByGoodsName(goodsName));
        return goods;
    }

    public static void main(String[] args) {
        String module = "test",exports = "test",with="with";
        System.out.println(new GoodsService().queryGoodsInfoByName("test"));
    }
}
複製代碼

 

接下來也要定義其模塊聲明:

module goods{
    requires order;
    requires pojo;
}複製代碼

由於暫時沒有其餘模塊依賴goods,因此模塊定義裏沒有聲明其導出的包。

至此咱們的三個模塊已經創建完成。

編譯和運行模塊

編譯和運行您能夠藉助IDE工具,可是爲了更透徹的理解模塊的定義,咱們先採用javac命令來編譯和運行咱們的模塊。

按照模塊的依賴順序,咱們依次編譯pojo->order->goods模塊。

編譯pojo模塊

咱們使用javac進行編譯,編譯命令以下:

javac -verbose --module-path target -d target\pojo pojo\src\*.java pojo\src\pojo\*.java

--module-path指定本次編譯依賴的外部模塊的搜索路徑,由於pojo模塊沒有外部依賴,這個參數在此其實能夠忽略。

-d指定編譯目標文件存放的目錄

-verbose打印詳細日誌便於咱們觀察編譯的具體過程

執行此命令控制檯打印信息系以下:

D:\code\mods>javac -verbose --module-path target -d target\pojo pojo\src\*.java pojo\src\pojo\*.java 
[語法分析開始時間 SimpleFileObject[D:\code\mods\pojo\src\module-info.java]] [語法分析已完成, 用時 23 毫秒] [語法分析開始時間 SimpleFileObject[D:\code\mods\pojo\src\pojo\Goods.java]] [語法分析已完成, 用時 9 毫秒] [語法分析開始時間 SimpleFileObject[D:\code\mods\pojo\src\pojo\Order.java]] [語法分析已完成, 用時 2 毫秒] [正在加載/modules/java.base/module-info.class] [正在加載/modules/java.base/java/util/List.class] [正在加載/modules/java.base/java/lang/Object.class] [正在加載/modules/java.base/java/lang/String.class] [正在加載/modules/java.base/java/time/LocalDateTime.class] [正在加載/modules/java.base/java/lang/Deprecated.class] [正在加載/modules/java.base/java/lang/Override.class] [正在加載/modules/java.base/java/lang/annotation/Annotation.class] [正在加載/modules/java.base/java/lang/annotation/Retention.class] [正在加載/modules/java.base/java/lang/annotation/RetentionPolicy.class] [正在加載/modules/java.base/java/lang/annotation/Target.class] [正在加載/modules/java.base/java/lang/annotation/ElementType.class] [正在檢查<匿名>] [已寫入DirectoryFileObject[target\pojo:module-info.class]] [正在檢查pojo.Goods] [正在加載/modules/java.base/java/io/Serializable.class] [正在加載/modules/java.base/java/lang/AutoCloseable.class] [正在加載/modules/java.base/java/lang/Byte.class] [正在加載/modules/java.base/java/lang/Character.class] [正在加載/modules/java.base/java/lang/Short.class] [正在加載/modules/java.base/java/lang/Long.class] [正在加載/modules/java.base/java/lang/Float.class] [正在加載/modules/java.base/java/lang/Integer.class] [正在加載/modules/java.base/java/lang/Double.class] [正在加載/modules/java.base/java/lang/Boolean.class] [正在加載/modules/java.base/java/lang/Void.class] [正在加載/modules/java.base/java/lang/invoke/StringConcatFactory.class] [正在加載/modules/java.base/java/lang/invoke/MethodHandles.class] [正在加載/modules/java.base/java/lang/invoke/MethodHandles$Lookup.class] [正在加載/modules/java.base/java/lang/invoke/MethodType.class] [正在加載/modules/java.base/java/lang/invoke/CallSite.class] [已寫入DirectoryFileObject[target\pojo:pojo/Goods.class]] [正在檢查pojo.Order] [正在加載/modules/java.base/java/time/temporal/Temporal.class] [正在加載/modules/java.base/java/time/temporal/TemporalAccessor.class] [正在加載/modules/java.base/java/time/temporal/TemporalAdjuster.class] [正在加載/modules/java.base/java/time/chrono/ChronoLocalDateTime.class] [正在加載/modules/java.base/java/lang/Comparable.class] [已寫入DirectoryFileObject[target\pojo:pojo/Order.class]] [共 485 毫秒]  

上面的輸出信息代表:雖然咱們的pojo沒有顯示聲明requires哪些模塊,可是系統默認導入了java.base模塊。也就是說咱們定義的模塊都隱士依賴java.base模塊,這僅僅是爲了導入常見的一些Java類庫。其餘輸出信息讀者能夠自行查看。

編譯order模塊

相似的執行下邊命令便可:

D:\code\mods>javac -verbose --module-path target -d target\order order\src\*.java order\src\order\*.java 
[語法分析開始時間 SimpleFileObject[D:\code\mods\order\src\module-info.java]] [語法分析已完成, 用時 34 毫秒] [語法分析開始時間 SimpleFileObject[D:\code\mods\order\src\order\OrderService.java]] [語法分析已完成, 用時 2 毫秒] [正在加載target\pojo\module-info.class] [正在加載/modules/java.base/module-info.class] [正在加載target\pojo\pojo\Order.class] [正在加載/modules/java.base/java/util/List.class] [正在加載/modules/java.base/java/lang/Object.class] [正在加載/modules/java.base/java/lang/String.class] [正在加載/modules/java.base/java/lang/Deprecated.class] [正在加載/modules/java.base/java/lang/annotation/Retention.class] [正在加載/modules/java.base/java/lang/annotation/RetentionPolicy.class] [正在加載/modules/java.base/java/lang/annotation/Target.class] [正在加載/modules/java.base/java/lang/annotation/ElementType.class] [正在檢查<匿名>] [已寫入DirectoryFileObject[target\order:module-info.class]] [正在檢查order.OrderService] [正在加載/modules/java.base/java/io/Serializable.class] [正在加載/modules/java.base/java/lang/AutoCloseable.class] [正在加載/modules/java.base/java/util/Collection.class] [正在加載/modules/java.base/java/lang/Iterable.class] [已寫入DirectoryFileObject[target\order:order/OrderService.class]] [共 684 毫秒] 

輸出信息咱們能夠清楚的看到,該模塊先加載target\pojo\module-info.class模塊而後加載java.base模塊。

編譯goods模塊

D:\code\mods>javac -verbose --module-path target -d target\goods goods\src\*.java goods\src\goods\*.java 
[語法分析開始時間 SimpleFileObject[D:\code\mods\goods\src\module-info.java]] [語法分析已完成, 用時 32 毫秒] [語法分析開始時間 SimpleFileObject[D:\code\mods\goods\src\goods\GoodsService.java]] [語法分析已完成, 用時 7 毫秒] [正在加載target\order\module-info.class] [正在加載target\pojo\module-info.class] [正在加載/modules/java.base/module-info.class] [正在加載target\order\order\OrderService.class] [正在加載target\pojo\pojo\Goods.class] [正在加載/modules/java.base/java/lang/Object.class] [正在加載/modules/java.base/java/lang/String.class] [正在加載/modules/java.base/java/lang/Deprecated.class] [正在加載/modules/java.base/java/lang/annotation/Retention.class] [正在加載/modules/java.base/java/lang/annotation/RetentionPolicy.class] [正在加載/modules/java.base/java/lang/annotation/Target.class] [正在加載/modules/java.base/java/lang/annotation/ElementType.class] [正在檢查<匿名>] [已寫入DirectoryFileObject[target\goods:module-info.class]] [正在檢查goods.GoodsService] [正在加載/modules/java.base/java/io/Serializable.class] [正在加載/modules/java.base/java/lang/AutoCloseable.class] [正在加載/modules/java.base/java/util/List.class] [正在加載target\pojo\pojo\Order.class] [正在加載/modules/java.base/java/lang/System.class] [正在加載/modules/java.base/java/io/PrintStream.class] [正在加載/modules/java.base/java/lang/Appendable.class] [正在加載/modules/java.base/java/io/Closeable.class] [正在加載/modules/java.base/java/io/FilterOutputStream.class] [正在加載/modules/java.base/java/io/OutputStream.class] [正在加載/modules/java.base/java/io/Flushable.class] [已寫入DirectoryFileObject[target\goods:goods/GoodsService.class]] [共 650 毫秒] 

至此咱們完成了全部模塊的編譯,如今咱們來看看編譯結果:


運行

咱們的運行入口在goods.GoodsService,運行命令以下:

D:\code\mods>java --module-path target -m goods/goods.GoodsService 
Goods{goodsName='test', orderList=[Order{createTime=2018-06-25T14:56:53.541093100, finishTime=2018-06-27T14:56:53.541093100, orderUser='gxf'}, Order{createTime= 2018-06-25T14:56:53.541093100, finishTime=2018-06-27T14:56:53.541093100, orderUser='gxf'}, Order{createTime=2018-06-25T14:56:53.541093100, finishTime=2018-06-27 T14:56:53.542053500, orderUser='gxf'}, Order{createTime=2018-06-25T14:56:53.542053500, finishTime=2018-06-27T14:56:53.542053500, orderUser='gxf'}, Order{createT ime=2018-06-25T14:56:53.542053500, finishTime=2018-06-27T14:56:53.542053500, orderUser='gxf'}]} 

--module-path指定模塊根目錄,也就是咱們編譯結果存放的根目錄

-m指定程序的入口,其用法是:

-m <module>/<main-class>

所以必須是帶模塊名而後是主類名。

好了,至此模塊的基礎知識咱們已經掌握的差很少了。若是你不喜歡命令行,則能夠考慮使用idea來進行編譯。在idea編譯的時候會報錯找不到模塊,根據提示將依賴模塊導入便可。


最後關於代碼下載

由於代碼量不多,建議你們仍是手動建立一遍,畢竟代碼均可以複製粘貼了。本身實踐一遍是否是印象更深入呢。

因爲篇幅和時間關係,關於模塊的其餘知識我會另起一篇再進行講述,但願你們天天都有進步。

相關文章
相關標籤/搜索