java9遷移注意問題總結(jié)
序
本文主要研究下遷移到j(luò)ava9的一些注意事項(xiàng)。
遷移種類
1、代碼不模塊化,先遷移到j(luò)dk9上,好利用jdk9的api
2、代碼同時(shí)也模塊化遷移
幾點(diǎn)注意事項(xiàng)
不可讀類
比如sun.security.x509,在java9中歸到j(luò)ava.base模塊中,但是該模塊沒有export該package
可以通過運(yùn)行的時(shí)候添加--add-exports java.base/sun.security.x509=ALL-UNNAMED來修改exports設(shè)定
內(nèi)部類
比如sun.misc.Unsafe,原本只想讓oracle jdk team來使用,不過由于這些類應(yīng)用太廣泛了,為了向后兼容,java9做了妥協(xié),只是將這些類歸到了jdk.unsupported模塊,并沒有限定其可讀性。
➜ ~ java -d jdk.unsupported jdk.unsupported@9 exports com.sun.nio.file exports sun.misc exports sun.reflect requires java.base mandated opens sun.misc opens sun.reflect
刪除的類
java9刪除了sun.misc.BASE64Encoder,這種情況只能改用其他api,比如java.util.Base64
classpath vs module-path
java9引入了模塊系統(tǒng),同時(shí)自身的jdk也模塊化了,引入了module-path,來屏蔽classpath,也就是說在java9優(yōu)先使用module-path,畢竟jdk本身都模塊化了,應(yīng)用本身沒有模塊化的話,java9通過unnamed modules及automatic modules機(jī)制來隱式模塊化,當(dāng)然classpath在java9上還能繼續(xù)使用,比如配合module-path使用等。
沒有模塊化的jar在classpath會被歸到unnamed modules;在module-path則會被自動創(chuàng)建為automatic modules(一個(gè)automatic modules會聲明transitive依賴所有named和unnamed module,然后導(dǎo)出自身的package)
一個(gè)包名不能在多個(gè)模塊中出現(xiàn)(split packages)
因?yàn)槟K中可以exports指定包給其他模塊,如果多個(gè)模塊exports同樣的包名會造成混亂,特別若有其他類庫同時(shí)requires這兩個(gè)模塊,就不知道該引用那個(gè)模塊的了。
傳遞依賴
如果一個(gè)模塊的接口參數(shù)或返回類型使用了其他模塊的類,則建議requires transitive它依賴的模塊
小心循環(huán)依賴
在設(shè)計(jì)模塊的時(shí)候,要盡可能考慮到是否會有循環(huán)依賴的問題,如果有則需要重新設(shè)計(jì)
使用services來實(shí)現(xiàn)optional依賴
services特別適合用來解耦調(diào)用方與實(shí)現(xiàn)類依賴的問題,如果接口有多種實(shí)現(xiàn)類,調(diào)用方不必要requires所有的實(shí)現(xiàn)類,只需要requires接口即可,使用services類型來加載實(shí)現(xiàn)類的實(shí)例。通過在module-path去動態(tài)添加實(shí)現(xiàn)模塊實(shí)現(xiàn)解耦。
模塊版本管理
module-info.java不支持聲明版本號,但是創(chuàng)建jar包的時(shí)候,可以通過--module-version設(shè)置。不過模塊系統(tǒng)查找模塊的時(shí)候還是使用模塊名來查找(如果module-path里頭有多個(gè)重名模塊,則模塊系統(tǒng)知會使用找到的第一個(gè),自動忽略后續(xù)的同名模塊),版本依賴問題不在模塊系統(tǒng)解決范疇內(nèi),交由maven之類的依賴管理工具去管理。
模塊資源訪問
模塊化之后資源文件也收到保護(hù),只能由該模塊去訪問本模塊自身的資源文件,如果需要跨模塊訪問,也必須借助ModuleLayer找到目標(biāo)模塊,再調(diào)用目標(biāo)模塊去加載該模塊的資源文件。
反射的使用
這里涉及到deep reflection問題,所謂的deep reflection就是通過反射去調(diào)用一個(gè)class的非public元素。module-info.java的exports聲明package只是允許該package直接所屬的類允許訪問其public元素,并不允許反射調(diào)用非public元素。
反射在模塊系統(tǒng)里頭需要特殊聲明才允許使用(使用opens聲明允許deep reflection),這樣就導(dǎo)致很多使用反射的類庫諸如spring,需要額外配置才能遷移到j(luò)ava9。解決方案有兩個(gè):一個(gè)是opens package包名給需要反射的模塊,比如spring.beans等;一個(gè)就是直接opens整個(gè)模塊。
默認(rèn)--illegal-access=permit,同時(shí)該設(shè)置只適用于java9之前的package在java9被不允許訪問,不適用于java9中新的不允許訪問的package.(建議遷移到模塊化系統(tǒng)時(shí)設(shè)置為deny)
不過就是在模塊系統(tǒng)中包名不一樣就屬于不同的包,沒有繼承關(guān)系,比如com.service.func1與com.service.func2這兩個(gè)是不同的包,你不能只opens com.service,必須分別指定這樣就導(dǎo)致需要open的的package比較多。因此open整個(gè)module可能更省事一點(diǎn),但也屬于比較粗暴的做法。上面的做法是在原來module-info.java里頭去做修改,另外一種是在執(zhí)行java或javac的時(shí)候通過指定的命令來修改原來的關(guān)系。比如
java ... --add-opens source-module/source-package=target-module
如果需要導(dǎo)出給unnamed modules,則target-module為ALL-UNNAMED
當(dāng)然如果是新的系統(tǒng),那就不建議使用反射了,可以使用MethodHandles及VarHandles。
常見問題和措施
ClassNotFoundException/NoClassDefFoundError
比如javax.xml.bind.JAXBException,JAXB已經(jīng)歸入到j(luò)ava.xml.bind模塊,在java命名后面添加
--add-modules java.xml.bind
如果圖省事,把$JAVA_HOME及所有第三方類庫添加到module-path,然后來個(gè)
--add-modules ALL-MODULE-PATH
illegal reflective access by xxx to method java.lang.ClassLoader.defineClass
反射原因引起,由于舊系統(tǒng)沒有module-info,因此在java命名添加參數(shù)加以修改
--add-opens java.base/java.lang=ALL-UNNAMED
確定依賴的模塊
通過IDE或者jdeps分析
jdeps --class-path 'classes/lib/*' -recursive -summary app.jar
jdeps只是靜態(tài)代碼分析,如果有使用反射用的類jdeps分析不出來,需要自己手工requires,如果dependency是optional的,可以requires static
對模塊單元測試的可讀性問題
如果單元測試時(shí)單獨(dú)模塊的話,可以在運(yùn)行時(shí)通過--add-exports或--add-opens來授予單元測試模塊對目標(biāo)模塊的可讀性及反射能力。另外由于split packages問題,單元測試類的包名不能跟目標(biāo)模塊包名重復(fù)。原來maven工程那種test
小結(jié)
可以分兩步走遷移到j(luò)ava9,首先是先不模塊化,只先跑在jdk9上;然后再模塊化。
相關(guān)文章
Kafka的安裝及接入SpringBoot的詳細(xì)過程
Kafka 是一種高性能、分布式的消息隊(duì)列系統(tǒng),最初由 LinkedIn 公司開發(fā),并于2011年成為 Apache 頂級項(xiàng)目,這篇文章主要介紹了Kafka的安裝及接入SpringBoot,需要的朋友可以參考下2024-05-05Java Lock鎖多線程中實(shí)現(xiàn)流水線任務(wù)
這篇文章主要介紹了Java Lock鎖多線程中實(shí)現(xiàn)流水線任務(wù),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05Java文件操作工具類fileUtil實(shí)例【文件增刪改,復(fù)制等】
這篇文章主要介紹了Java文件操作工具類fileUtil,結(jié)合實(shí)例形式分析了java針對文件進(jìn)行讀取、增加、刪除、修改、復(fù)制等操作的相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-10-10泛型的類型擦除后fastjson反序列化時(shí)如何還原詳解
這篇文章主要為大家介紹了泛型的類型擦除后fastjson反序列化時(shí)如何還原詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11JavaWeb dbutils執(zhí)行sql命令并遍歷結(jié)果集時(shí)不能查到內(nèi)容的原因分析
這篇文章主要介紹了JavaWeb dbutils執(zhí)行sql命令并遍歷結(jié)果集時(shí)不能查到內(nèi)容的原因分析及簡單處理方法,文中給大家介紹了javaweb中dbutils的使用,需要的朋友可以參考下2017-12-12springboot驗(yàn)證碼的生成與驗(yàn)證的兩種方法
本文主要介紹了springboot驗(yàn)證碼的生成與驗(yàn)證的兩種方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06利用JSONObject.toJSONString()包含或排除指定的屬性
這篇文章主要介紹了利用JSONObject.toJSONString()包含或排除指定的屬性,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03關(guān)于Idea中的.properties文件顯示問題
這篇文章主要介紹了關(guān)于Idea中的.properties文件顯示問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07