nicolai parlog是 一位熱情的軟體工程師,數字版權與開源軟體的狂熱擁護者;他對assertj、controlsfx、findbugs及property alliance等項目都做出過重要的貢獻。近日,parlog就jigsaw項目撰寫了一篇文章,談到了jigsaw項目的一些不足以及改進之處。 jigsaw項目有着雄心勃勃的宏偉目标,其目标之一就是徹底擺脫極易出錯且問題多多的類路徑機制中的jar地獄問題。不過,雖然該項目的其他目标會在不 久的将來得以實作,但解決jar地獄問題這一目标似乎并不是那麼容易的。
為了更好地了解我們接下來要讨論的内容,首先來看一下jar地獄問題,接下來介紹jigsaw項目将會解決問題的哪些方面,以及為什麼說 jigsaw所嘗試解決的問題并不會對整個問題域産生本質的影響。最後,我們來看一下官方對于這個話題的立場,并給出如何防止出現子產品地獄的提案。
jar地獄存在着如下循環問題:
表述不清以及傳遞性依賴
遮蔽
版本沖突
複雜的類加載
根據建構工具與元件系統(jdk開發者稱之為容器)為我們所帶來的諸多功能與特性,我們可以認為表述不清以及傳遞性依賴問題已經在很大程度上得到了 解決,遮蔽問題至少得到了緩解,而複雜的類加載也不再是老生常談的問題了。這樣,版本沖突就成為jar地獄中最為嚴重的一個問題了,它影響到了很多很多項 目每天的更新決策。
我之前曾就jigsaw項目會為java 9帶來哪些新特性專門寫過文章進行過介紹,不過這裡将從不同的視角進行闡述。首先,它會受到目前的早期通路建構版的影響;其次,我們這裡隻從與jar/子產品地獄相關的角度進行介紹。
jigsaw為java帶來的核心概念就是子產品化。簡而言之,子產品就像jar一樣,同時帶有一些附加資訊與特性。這些資訊包含了子產品的名字以及子產品所依賴的其他子產品的名字。
當編譯器與jvm在處理子產品時,他們會解析這些資訊。在編譯或啟動時,他們會通過子產品路徑傳遞性解析所有依賴。總體來說,這類似于類路徑掃描,不過 現在尋找的是整個子產品而非單個類,對于jvm來說,這是在啟動期而非運作期進行的。如果在子產品路徑上無法找到所有依賴,那麼解析子產品的傳遞性依賴就會失 敗。這顯然可以解決表述不清,以及無休止的傳遞性依賴的問題。我認為這是個很棒的做法,java語言現在正式知道關于依賴的資訊了,所有工具(編譯器與 jvm等)都能了解這一點并正常使用!不過,我認為這并不會對開發者每天的工作産生多少積極的影響,因為現在很多既有的基礎設施都已經解決這個問題了,比 如說建構工具等。
jigsaw消除了遮蔽的問題。子產品系統可以確定每個依賴都會被另一個子產品所實作,每個子產品都會讀取至多一個子產品,定義了同名包的子產品之間并不會互相幹擾。更準确地說,子產品系統在遇到模糊不清的情況時就會終止并報錯,比如說兩個子產品将相同的包導出到相同子產品中。
我們認為第三方庫的版本沖突是jar地獄最為難以解決的問題。最直接的解決方案就是一個子產品系統能夠加載同一個子產品的不同版本。這需要確定這些版本 之間不存在互互相動的情況。問題在于:在單個配置中,沒必要支援一個子產品的多個版本。實際上,目前的建構既不會建立,也無法了解子產品版本資訊。曾有人使用 了一些變通辦法。最醜陋,同時也是最可行的辦法就是重命名出現沖突的構件,這樣他們就不再是相同子產品的兩個不同版本了,而是兩個完全不同的子產品。不過,這 種做法最後證明也是行不通的。顯然,確定“定義了同名包的子產品之間不會互相幹擾”是在兩個子產品導出相同包時拒絕任何啟動配置來實作的。即便沒有子產品讀取他 們亦如此!
子產品與類加載器之間如何互動以及如何改變類加載的複雜性是個很棘手的問題。實際上,子產品系統對子產品與類加載器之間的關系并沒有做多少限制。類加載器 可以從一個子產品或是多個子產品來加載類型,隻要子產品之間不存在互相幹擾的情況,并且每個子產品中的類型隻由一個加載器加載即可。是以,類加載器與子產品之間是一 對多的關系。
既然依賴與遮蔽問題已經得到了解決,并且類加載問題也得到了改進,那我為何還要讨論子產品地獄呢?就是因為版本沖突麼?沒錯!如果jigsaw想要解 決jar地獄問題,它就需要特别注意版本沖突問題。否則,很多項目并不會出現什麼起色。他們依然要面對版本沖突問題,并且會陷入到自定義類加載器的夢魇 中。
我的提案是讓開發者與建構工具能夠傳遞一些額外的資訊,這些資訊能夠解決一些含糊不清的問題。傳遞這種資訊的兩種常見方式是指令行與配置檔案。如果 使用指令行參數,那麼每次啟動時都需要輸入一次。根據資訊的多少以及項目的規模,這種做法可能會變得非常乏味。可以通過建構工具來建立配置檔案,然後再通 過指令行指定配置檔案。這看起來是個不錯的解決方案。目前,初始子產品與所有的傳遞性依賴都是通過單個配置來解析的,這形成了單獨的一個層次。不過,我們可 以在運作期将相同子產品的多個版本加載到不同層次中,這正是元件系統要做的事情。總的來說,我的建議就是通過多個層次來顯式指定配置。
====================================分割線================================