JDK先生最近有點煩
1 JDK 先生有點煩
JDK先生有點煩, 因為最近幾個刺兒頭程序經常找茬兒, 抱怨的還是classpath, jar 文件, package這幾個JDK賴以生存、 引以為傲的基礎設施。
想當年java誕生的時候, package 幫助程序員把java 類更好地組織起來, jar 文件把class文件打成壓縮包,而classpath 這么多年一直兢兢業業地查找類文件,從來沒出過差錯。 為啥要抱怨他們呢?
前天用戶系統跑過來說,他有兩個package ,com.foo.db.api.和 com.foo.db.impl, 他期望大家只使用api包的UserDao, 可是總有一些不著調的程序員還去直接使用impl包, 屢禁不止啊。
用戶系統帶著怨氣地問道: 你就沒有辦法讓impl包也變成對外私有的? 你要是再不支持,我們都要轉到OGSi 去了啊,到時候你后悔都來不及!
還有,昨天訂票系統跑來說,他有兩個模塊,模塊A 依賴json_1.1.jar,模塊B依賴 json_2.0.jar , 可是這兩個jar 互不兼容, 怎么把它們放到classpath上?
JDK 覺得訂票系統很變態,怎么會出現這樣的代碼,這不是自己折磨自己嗎? 但轉念一想,主要的問題還是自己的classpath, 這個所謂的classpath 是個平鋪的線性結構, 而jar 之間的依賴關系應該是個有向圖啊!
今天還有個家伙說他要開發物聯網應用, 內存受限, 他發現JDK和JRE太大了,動輒上百M, 更要命的是其中有不少東西他們并不用, 例如界面相關的jar , 但是又沒法從JDK中去除。 能不能按照需要裁剪一下JDK呢?
如果說前面兩個要求還算合理, 這個老兄的要求簡直就是一場革命, JDK自己革自己的命。
2 模塊化
雖然JDK已經非常成熟,但是用戶的需求不能置之不理。
JDK閉關思考了半月, 終于憋出來一個大招:做粗粒度的模塊化!
他把各位刺兒頭招來商議。
“模塊化? 還粗粒度? ” 一聽到這個消息, 訂單系統就跳了起來,生怕把自己給改亂了。
“是啊,模塊一般指的是一個獨立的單元, 它精確地聲明了對外的接口和依賴。 你們想想,人類在開發中基本上都是把jar文件作為一個個的‘模塊’, 每個jar文件中包含了一些package , 但是 jar 文件本質上還是一堆.class文件的壓縮而已。”
“那該怎么辦?” 用戶系統好奇心被激發了,它特別想做package的權限控制。
“最簡單的辦法,可以在jar包中添加一個聲明性的文件, 這個文件定義模塊名,它對外提供的接口,和依賴, 像這樣:”
用戶系統很激動, 這簡直就是為了他量身定做的: “嗯,這很容易理解, 這個jar 的模塊名叫做com.foo.db, 依賴另外一個模塊 java.sql , 這個export 就是說別人只能訪問com.foo.db.api這個package下面的類, 像com.foo.db.impl 就不能訪問了,對吧?”
com.foo.db.jar 文件的內容如下:
- module-def.xml
- com.foo.db.api.XXXX.class
- com.foo.db.api.XXXX.class
- ......
- com.foo.db.impl.XXXX.class
- com.foo.db.impl.XXXX.class
- ......
JDK 贊許地說: “沒錯, 這就是所謂粗粒度的模塊, 原來的java class 也可以稱為一個模塊,但是粒度太細了, 現在我們把一組類封裝到一個jar 文件中,再加一個聲明文件, 就變成了一個粗粒度模塊。當然你肯定能想到,我自己也得做增強嘍, 必須得能識別模塊定義,并且正確的設置訪問權限。”
用戶系統說: “哎呀, 我其實最討厭又臭又長的xml 了, 能不能用java 描述呢,就叫做module-info.java吧”
JDK笑了: “看來你小子想得挺深的。 我也喜歡這樣清爽的表達, 只不過得把java 語法也增強了。增加像module , requries, exports這樣的關鍵字才行。”
現在: com.foo.db.jar 文件的內容如下:
- module-info.class
- com.foo.db.api.XXXX
- com.foo.db.api.XXXX
- ......
- com.foo.db.impl.XXXX
- com.foo.db.impl.XXXX
- ......
3 JDK自身的革命
開發物聯網的小伙子問道: “JDK先生, 你自己是不是也要搞成模塊化啊 , 這樣我就可以裁剪出我使用的模塊了。”
“是啊, 你們上層要是模塊化了, 我肯定也得這么搞,并且我還得先搞出來, 這樣你們好使用啊。這對我來說,是一場巨大的革命啊, 我得把我成千上萬的類給捋一捋,形成層次分明,隔離良好的模塊, 我現在才總結了一部分: java.desktop , java.xml, java.sql , java.naming, java.logging, java.scripting......”
訂單系統打斷說: "慢著, 難道讓我在每個模塊中都導入所有的JDK的基本模塊嗎? 這不把人給累死?"
JDK 說: “不不, 這個問題我也考慮過了,其實可以引入一個隱式的依賴嘛, 我把JDK中最重要的核心模塊組織起來,形成一個java.base 模塊,其他模塊都隱式的依賴它就行了, 就像你的java類不用extend Object 一樣, JDK會自動給你加上。”
4 遷移
用戶系統說: “ 模塊化的想法很不錯, 解決了我的問題。 可是現有的大部分程序和jar包都沒有實現模塊化, 單單自己實現模塊化有什么用, 你去require 誰? 你export出去的接口被誰用? ”
大家都向用戶系統投來了佩服的目光, 這是個非常現實的問題。
模塊化僅僅有JDK的改變還不夠, 除非大家都用起來,要不然還是無法實施。
log4j 跳出說: “是啊是啊, 你們都遷移成模塊了, 我一直沒改,該怎么辦?”
JDK說: “ log4j 你不用擔心, 肯定得有一種讓大家慢慢遷移到‘模塊’的路徑才行, 就說你吧, 還沒有模塊化,但是用戶系統想擁抱模塊化, 他要require你,該怎么辦?”
“也許我可以臨時的給他們起個名字,例如log4j-module , 可是我的模塊怎么才能知道這個'臨時模塊'的存在呢?” 用戶系統說
“想想classpath , 我們可以搞個modulepath, 只要加入到這個modulepath的jar文件,例如log4j.jar , 就自動認為這是一個module (雖然他沒有module-info.java聲明) , 這樣你就可以requrie log4j 來使用它了。”
"妙啊,這可以讓大家慢慢的遷移, 我可以先把我的應用轉化為模塊 , 如果哪個類庫還沒擁抱模塊化, 我就把它放到modulepath中,讓它自動成為一個模塊, 這樣我就可以require了!"
用戶系統對JDK的方法非常佩服。
“別高興的太早” JDK說, “一個類庫一旦成為自動的模快, 那它就能訪問所有的模塊,因為我們不知道它到底依賴誰, 為了能讓大家遷移到模塊化,這也算是一個代價吧。 ”
“對了,要是只有JDK實現了模塊化, 但是我們上層的應用還沒有開始遷移, 能在新的JDK上運行嗎? ” 訂單系統擔憂的問道。
“那必須得運行,不是自夸,我比較牛的一點就是向后兼容性, 早期的代碼甚至不用修改就可以在***的JRE上運行, 新的特性可不能破壞這種兼容性!”
“那該怎么搞? ”
“很簡單, 我會把所有這些沒有遷移的類庫都放置到一個叫做unnamed模塊當中, 這樣概念上就統一了。 ”
“不錯不錯, 聽起來可行” 大家紛紛表示贊成 “要不試一試?”
“心急吃不了熱豆腐, 我今天召集大家來也是把主要的想法給大家分享下, 說起來簡單, 里邊有很多細節我得好好想想才行, 大家耐心地等待下一個版本的發行吧!”
后記: 本文介紹的就是Java9的新特性: 模塊化的一些概念, 還有很多其他的細節,感興趣的同學可以點擊閱讀原文去openjdk 的網站上去看看 。
【本文為51CTO專欄作者“劉欣”的原創稿件,轉載請通過作者微信公眾號coderising獲取授權】