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中也有少量獨有功能。
由於是源碼開放,用戶可以從
http://hg.openjdk.java.net/jdk8u/jdk8u-dev將源代碼clone下來自己編譯OpenJDK
或者下載源碼包,http://jdk7.java.net/source.html,解壓后自己編譯。
並且基於這些可復用的源碼,誕生了很多其他版本的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里面是沒有的,所以引發了上面的編譯錯誤。解決方式也很簡單,主要如下幾種做法:
- 不要使用javafx.util這種OpenJDK里面沒有的包;
- 本地開發環境直接使用OpenJDK,或者部署時服務器或者容器上使用與本地開發環境版本一致的Oracle JDK,但這會涉及到版權問題;
- 下載javafx-sdk到服務器,編譯時將javafx-sdk位置作為--module-path參數傳入;l
- 在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包布署。