前言
對于模塊的定義,相信小伙伴們都不會有太大的疑問,這里引用JDK中模塊的定義:一組可重用的相關(guān)包和資源,以及模塊的描述信息。直白點的描述就是:用一種比package更大級別的組織方法來管理我們的類。講到它的作用是組織管理,大家是不是就開始聯(lián)想到了OSGi,JBoss Module,Maven,甚至是微服務(wù)呢?首先,這幾種形式都是用于軟件的模塊化方法,只是應(yīng)用的場景和各自的長處有所不同,指北君用一張圖表來做一下簡單對比:
模塊化方式
- 微服務(wù):服務(wù)粒度的組織方法,比模塊級別更高
- Maven:依賴管理工具
變化
首先,作為一頭猿,最直接的編碼IDE工具,以Eclipse為例,我們新建一個標(biāo)準(zhǔn)的Java工程,切換下JDK進(jìn)行對比,
JDK庫-JAVA11
JDK庫-JAVA8
首先我們會發(fā)現(xiàn):項目使用中的JDK11的庫中比之前JDK8多出很多條目來,而且和之前的完全不一樣了。這就是JDK引入模塊后,將原來的庫進(jìn)行了拆分。為什么要拆呢?
- 伴隨Java的版本升級,包越來越多,功能越來越多,組織管理越來越難
- 一些jar包太大(比如rt.jar),不利于在小型設(shè)備中運(yùn)行
- 無法定義只能在模塊內(nèi)部訪問的接口,只能通過一些額外的約束,比如文檔,internal等形式進(jìn)行提示
JDK是如何對原有的jar進(jìn)行拆分的呢?我們查看模塊名稱會發(fā)現(xiàn),所有模塊分成兩類:java開頭和jdk開頭,這是按照J(rèn)AVA的JRE和JDK范圍進(jìn)行的大類別的劃分,然后再按照功能級做進(jìn)一步劃分。除了在開發(fā)者環(huán)境中引入的庫發(fā)生變化外,在JDK的安裝目錄中也有類似的變化
JDK安裝目錄對比
明顯是jre目錄不在了,增加了jmods目錄,lib下面的組織形式也發(fā)生了較大的變化。
可以做什么
前面我們介紹模塊系統(tǒng)引入后帶來的直觀的變化,這一節(jié)指北君要介紹模塊系統(tǒng)的作用,我們先來看一下模塊的定義里面包含的要素:
- 名稱 – 模塊名
- 依賴 - 本模塊依賴的一系列其他模塊
- 公共包 - 外部可訪問的所有包
- 提供的服務(wù) - 提供其他模塊消費(fèi)的服務(wù)實現(xiàn)
- 消費(fèi)的服務(wù) - 允許當(dāng)前模塊作為服務(wù)消費(fèi)者
- 反射權(quán)限 - 顯式允許其他類通過反射訪問的包的私有成員
從定義的要素中我們發(fā)現(xiàn):模塊不僅僅是提供的一直包、類的組織方式,更重要的是提供了以前無法支持的安全訪問控制。
模塊的類型
有四種類型的模塊
- 系統(tǒng)模塊:JDK定義的模塊,可以通過下面命令來獲取
java --list-modules
- 應(yīng)用模塊:我們開發(fā)的應(yīng)用對應(yīng)的模塊,通過module-info.java定義并編譯成對應(yīng)的class
- 自動模塊:通過模塊路徑加載的第三方j(luò)ar包
- 未命名模塊:不是通過模塊路徑加載的第三方j(luò)ar
模塊的聲明
要創(chuàng)建一個模塊,需要在包的根路徑下創(chuàng)建module-info.java(注意名稱是固定的),如果按照Class的方式創(chuàng)建會出現(xiàn)名稱校驗失敗,這時候可以直接創(chuàng)建一個文件命名為module-info.java。
module moduleName {
}
使用關(guān)鍵字module定義,模塊名稱按照約定為通過點號"."分割的小寫詞組,比如java.base, north.sample。
requires
requires用來管理模塊的依賴關(guān)系,我們一旦采用了模塊,我們會發(fā)現(xiàn)原來的有些類會出現(xiàn)編譯錯誤,這是因為我們的代碼中應(yīng)用了默認(rèn)之外的包,需要通過requires關(guān)鍵詞引入我們引用的模塊。
module north.smaple{
requires java.scripting;
}
使用requires還可以使用兩個修飾詞:static,transitive,
- static用來定義一個可選的模塊依賴,僅當(dāng)編譯時有依賴才引用
- transitive 表示下游的模塊不用顯式聲明,就可以使用上級模塊中通過transitive關(guān)鍵字引入的模塊
exports
通過exports我們可以定義可訪問的接口
module north.smaple{
exports north.jdk.scripting;
}
我們還可以通過exports…to來定義接口開放的目標(biāo)對象。
uses
定義使用的服務(wù),以java.sql模塊代碼為例:
module java.sql {
...
exports java.sql;
exports javax.sql;
uses java.sql.Driver;
}
為什么對服務(wù)特殊處理呢?各位小伙伴是不是覺得:requires就能夠定義訪問依賴,為啥還要用uses呢?這是因為,uses相對于requires是存在區(qū)別的。比如,我們的服務(wù)接口實現(xiàn)和服務(wù)接口不在同一個模塊中,如果用requires則需要對所有的實現(xiàn)模塊引入,如果使用uses只需要引入接口所在的模塊就行了,是不是很方便呢!而且有時我們都不知道接口的實現(xiàn)模塊,這時候都無法通過requires引入。
provide
如果需要定義外部可使用的服務(wù),則通過provide聲明,語法是 provides <服務(wù)接口> with <服務(wù)實現(xiàn)>
module north.smaple{
provides ISampleService with ISampleServiceImpl;
}
open/opens
open是用來定義模塊的被外部模塊通過反射調(diào)用的權(quán)限,在這之前我們可以通過反射調(diào)用任何我們想要訪問的類型和成員,甚至是私有屬性的。在使用模塊系統(tǒng)后,如果我們要保持之前的全訪問,可以直接在module前添加open關(guān)鍵字。
open module north.smaple{
...
}
如果我們有針對性的開放反射權(quán)限,則通過opens
module north.smaple{
opens north.jdk.scripting;
}
opens還支持更嚴(yán)格的定義 opens ... to ...
總結(jié)
關(guān)于Java的模塊系統(tǒng),我們今天就學(xué)習(xí)到這里,相信經(jīng)過代碼示例和講解,各位小伙伴已經(jīng)可以將模塊系統(tǒng)應(yīng)用到項目中了。
-
模塊
+關(guān)注
關(guān)注
7文章
2670瀏覽量
47340 -
JAVA
+關(guān)注
關(guān)注
19文章
2958瀏覽量
104547 -
軟件
+關(guān)注
關(guān)注
69文章
4774瀏覽量
87160 -
編碼
+關(guān)注
關(guān)注
6文章
935瀏覽量
54762
發(fā)布評論請先 登錄
相關(guān)推薦
評論