1. 程式人生 > 其它 >一場因OpenJDK引發的血案 之JavaFx

一場因OpenJDK引發的血案 之JavaFx

https://zhuanlan.zhihu.com/p/103765203

案發現場

最近做了個專案,本地除錯通過了,可在伺服器上部署時卻編譯失敗,報錯如下

編譯失敗的原因是缺少javafx.util。

package javafx.util does not exist

原因分析

檢視程式碼,是因為使用了javafx.util中的Pair類

那為什麼本地可以編譯通過了?我本看下本地jdk版本,開啟一個shell視窗輸入

java --version

結果如下

再看看伺服器上jdk的版本

問題浮出水面了,伺服器上用的是OpenJDK。它跟本地開發環境所用的JDK還是有區別的,應該說它是一個不完整的jdk的開源版本,JDK有的東西它不一定有。具體區別體現在哪裡了?

JDK與OpenJDK的區別

前世今生

JDK(Java Development Kit)是Java平臺程式設計中使用的軟體開發環境。它包含一個完整的Java執行時環境,即JRE,以及一些Java開發工具(如javac/java/jdb等)與基礎類庫等。針對不同使用場景,其有三個不同的產品形態:

  • SE(J2SE),standard edition,標準版,是我們通常用的一個版本,從JDK 5.0開始,改名為Java SE。
  • EE(J2EE),enterprise edition,企業版,使用這種JDK開發J2EE應用程式,從JDK 5.0開始,改名為Java EE。
  • ME(J2ME),micro edition,主要用於移動裝置、嵌入式裝置上的java應用程式,從JDK 5.0開始,改名為Java ME。

本文講的是最常用的標準版。我們常說的JDK有兩種叫法,早期叫做Sun JDK,後來Sun被Oracle收購了,又改叫Oracle JDK,本文統稱Oracle JDK。

我們回顧下Oracle JDK的版本

  • JDK Beta - 1995
  • JDK 1.0 - 1996年1月
  • JDK 1.1 - 1997年2月
  • J2SE 1.2 - 1998年12月
  • J2SE 1.3 - 2000年5月
  • J2SE 1.4 - 2002年2月
  • J2SE 5.0 - 2004年9月
  • Java SE 6 - 2006年12月
  • Java SE 7 - 2011年7月(再次之前先將主分支作為OpenJDK 6開源)
  • Java SE 8(LTS) - 2014年3月
  • Java SE 9 - 2017年9月
  • Java SE 10(18.3) - 2018年3月
  • Java SE 11(18.9 LTS) - 2018年9月
  • Java SE 12(19.3) - 2019年3月

其中斜體版本不再支援。在開發JDK7的時候,OpenJDK已經成為JDK7的主幹開發,並在2007年開源,是為OpenJDK 6。此後Sun JDK7是在OpenJDK7的基礎上釋出的,其大部分原始碼都相同,只有少部分原始碼被替換掉。

其實Sun自JDK 1.5之後就開始以Java Research License(JRL)的形式公佈過Java原始碼,主要用於研究人員閱讀(JRL許可證的開放原始碼至JDK 1.6 Update 23為止)。把這些JRL許可證形式的OracleJDK原始碼和對應版本的OpenJDK原始碼進行比較,發現除了檔案頭的版權註釋之外,其餘程式碼基本上都是相同的,只有字型渲染部分存在一點差異,Oracle JDK採用了商業實現,而OpenJDK使用的是開源的FreeType。

當然,這裡的“相同”是建立在兩者共有的元件基礎上的,Oracle JDK中還會存在一些Open JDK沒有的、商用閉源的功能,例如Flight Recorder,OpenJDK中也有少量獨有功能。

由於是原始碼開放,使用者可以從

將原始碼clone下來自己編譯OpenJDK

或者下載原始碼包,,解壓後自己編譯。

並且基於這些可複用的原始碼,誕生了很多其他版本的JDK,例如IcedTea、UltraViolet都是從OpenJDK原始碼衍生出的發行版,一些大公司也有自己的版本如Amazon Corretto,alijdk等。

自此OpenJDK成為由Oracle,OpenJDK和Java社群開發共同維護的單獨的一個專案,目前主要版本如下

OpenJDK 6專案 - 基於JDK 7,但經過修改後提供了Java 6的開源版本
OpenJDK 7專案 - 2011年7月28日
OpenJDK 7u專案 - 該專案開發Java Development Kit 7的更新
OpenJDK 8專案 - 2014年3月18日
OpenJDK 8u專案 - 該專案開發Java Development Kit 8的更新
OpenJDK 9專案 - 2017年9月21日
JDK專案於2018年3月10日至20日釋出
JDK專案於2018年9月11日至25日釋出
JDK專案釋出12 - 穩定階段

可以說OpenJDK是自jdk7版以來Java標準版的官方參考實現。它和Oracle JDK的主要區別如下:

OpenJDK不包含Deployment(部署)功能

部署的功能包括:Browser Plugin、Java Web Start、以及Java控制面板,這些功能在OpenJDK中是找不到的。

OpenJDK原始碼不完整

這個很容易想到,在採用GPL協議的OpenJDK中,SUN JDK的一部分原始碼因為產權的問題無法開放給OpenJDK使用,其中最主要的部份就是JMX中的可選元件SNMP部份的程式碼。

部分原始碼用開原始碼替換

出於產權的問題,很多產權不是SUN的原始碼被替換成一些功能相同的開原始碼,比如前面跳到的說字型渲染部分的實現在OpenJDK中使用Free Type代替。

OpenJDK只包含最精簡的JDK

OpenJDK不包含其他的軟體包,比如Rhino Java DB JAXP……,並且可以分離的軟體包也都是儘量的分離,但是這些大多是自由軟體,你可以自己下載安裝。包括這裡遇到的javafx,也可以自己下載安裝到openJDK的類庫中。

功能上

應該說,兩者之間超過99%的功能都是相同的,細微的區別在於Oracle JDK具有Flight Recorder,Java Mission Control,Application Class-Data Sharing 功能以及更多的垃圾收集選項和更好的渲染器,而OpenJDK具有Font Renderer功能。




許可證

Oracle JDK:GPL(通用公共許可證)

OpenJDK:GNU,GPL

在沒有商業許可的情況下,在2019年1月之後釋出的Oracle Java SE 8的公開更新將無法用於商業用途。但是,OpenJDK是完全開源的,可以自由使用。正因如此,一般伺服器上用的都是OpenJDK。

穩定性

Oracle JDK構建過程是基於OpenJDK的,所以他們之間並沒有技術差別。只是OpenJDK由於版本釋出比較頻繁,可能會遇到不穩定的問題。根據社群反饋,也有一些OpenJDK使用者遇到了效能問題。而Oracle JDK作為商業軟體,在穩定性方面要好很多,或許OpenJDK就是給Oracle JDK踩坑用的吧,哈哈。

解決辦法

這裡的javafx.util包在jdk 1.8的類庫裡面有,但在OpenJDK 8裡面是沒有的,所以引發了上面的編譯錯誤。解決方式也很簡單,主要如下幾種做法:

  1. 不要使用javafx.util這種OpenJDK裡面沒有的包;
  2. 本地開發環境直接使用OpenJDK,或者部署時伺服器或者容器上使用與本地開發環境版本一致的Oracle JDK,但這會涉及到版權問題;
  3. 下載javafx-sdk到伺服器,編譯時將javafx-sdk位置作為--module-path引數傳入;l
  4. 在pom裡面顯式新增javafx依賴,這樣在伺服器上用mvn編譯時,會把它從maven中央倉庫拉到本地打包到你的工程裡。
<!-- https://mvnrepository.com/artifact/org.openjfx/javafx-base -->
<dependency>
    <groupId>org.openjfx</groupId>
    <artifactId>javafx-base</artifactId>
    <version>14-ea+7</version>
</dependency>

4. 本地編譯好,直接用jar包佈署。