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里面是没有的,所以引发了上面的编译错误。解决方式也很简单,主要如下几种做法:

  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包布署。

一场因OpenJDK引发的血案 之JavaFx的更多相关文章

  1. 一场由过滤器Filter引发的血案

    一场由过滤器Filter引发的血案 事件起因 本来应该是下图的登录界面 变成了这样 What's the fuck????? 抓狂 原因 解决方法: 在过滤器中给资源文件开个绿色通道

  2. [WCF]缺少一行代码引发的血案

    这是今天作项目支持的发现的一个关于WCF的问题,虽然最终我只是添加了一行代码就解决了这个问题,但是整个纠错过程是痛苦的,甚至最终发现这个问题都具有偶然性.具体来说,这是一个关于如何自动为服务接口(契约 ...

  3. dubbox微服务实例及引发的“血案”

    Dubbo 是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成. 主要核心部件: Remoting: 网络通信框架 ...

  4. Integer.parseInt 引发的血案

    Integer.parseInt 处理一个空字符串, 结果出错了, 程序没有注意到,搞了很久, 引发了血案啊!! 最后,终于 观察到了, 最后的部分: Caused by: java.lang.NoC ...

  5. Replication的犄角旮旯(六)-- 一个DDL引发的血案(上)(如何近似估算DDL操作进度)

    <Replication的犄角旮旯>系列导读 Replication的犄角旮旯(一)--变更订阅端表名的应用场景 Replication的犄角旮旯(二)--寻找订阅端丢失的记录 Repli ...

  6. Replication的犄角旮旯(七)-- 一个DDL引发的血案(下)(聊聊logreader的延迟)

    <Replication的犄角旮旯>系列导读 Replication的犄角旮旯(一)--变更订阅端表名的应用场景 Replication的犄角旮旯(二)--寻找订阅端丢失的记录 Repli ...

  7. 转:一个Sqrt函数引发的血案

    转自:http://www.cnblogs.com/pkuoliver/archive/2010/10/06/1844725.html 源码下载地址:http://diducoder.com/sotr ...

  8. 一个Sqrt函数引发的血案(转)

    作者: 码农1946  来源: 博客园  发布时间: 2013-10-09 11:37  阅读: 4556 次  推荐: 41   原文链接   [收藏]   好吧,我承认我标题党了,不过既然你来了, ...

  9. 一个字母引发的血案 java.io.File中mkdir()和mkdirs()

    一个字母引发的血案 明天开始放年假了,临放假前有个爬虫的任务,其中需要把网络图片保存到本地,很简单,马上写完了代码: //省略部分代码... Long fileId= (Long) data.get( ...

  10. form表单提交引发的血案

    最近,公司某条产品线上的一个功能出了问题:点击查询的时候,该页面在IE上直接卡死,chrome上会卡顿一段时间候提交表单进行查询.拿到这个bug单子以后,简单重现了下,基本上定位到是查询操作中的问题, ...

随机推荐

  1. iOS关于NSNotificationCenter通知使用小结

    常用的页面之间传值方式是参数,单例,通知,委托,以及其他全局变量等等.通知是一种广播形式,可以一对多通知传值.最近在项目中用的模块化开发, 通过封装抽取,将页面分为上中下三个模块.最简单的方式是把所有 ...

  2. 04-react的基本:条件渲染

    import reactDom from "react-dom" // 条件渲染 if else let loading = false // 写一个函数用于加载 const lo ...

  3. 14. Vue2 和 Vue3 区别

    主要分为四点: 1. Vue3 使用了 proxy 替代了 Object.defineProperty 实现响应式数据 ,所以 vue3 的性能得到了提升 : 2. Vue3 可以在 template ...

  4. 探索 PCI 转 PMC 载板转接卡:连接不同接口的桥梁

    探索 PCI 转 PMC 载板转接卡:连接不同接口的桥梁 在计算机硬件领域,各种接口和总线标准不断演进,以满足日益增长的性能和功能需求.在这个过程中,不同接口之间的转换设备应运而生,其中 PCI 转 ...

  5. 利用 Kubernetes 内置 PodTemplate 管理 Jenkins 构建节点

    作者:Rick Jenkins 可以很好地与 Kubernetes 集成,不管是控制器(controller)还是构建节点(agent),都能以 Pod 的形式运行在 Kubernetes 上. 熟悉 ...

  6. while循环和do循环、缓冲区、一维数组

    缓冲区 输入缓冲区 从键盘得到数据的时候用户输入的数据首先进入输入缓冲区,然后程序从输入缓冲区里获得数字,先进入输入缓冲区的数据必须先处理(类似排队),如果先进入输入缓冲区的数据无法处理,程序就得不到 ...

  7. ToDesk云电脑堪比万元PC?黑悟空、老头环及战锤40K实测体验!

    2009年,OnLive首次在旧金山游戏开发者大会推出"云游戏"的概念,但受限于当时的网络宽带技术,云游戏并不被十分看好.现如今,5G时代已然到来,数据通量和画质传输给予云游戏崛起 ...

  8. JS 数组转对象 对象转数组 对象数组互相转换 数组对象互相转换

    JS 数组转对象 对象转数组  对象数组互相转换  数组对象互相转换 声明一个函数,arr_obj ,里面接收一个参数,参数类型只接受对象或者数组 如果没有传递任何参数  或者 传递的参数类型不符合要 ...

  9. GoLand IDE 如何设置每次打开时先展示启动界面

    GoLand IDE 如何设置每次打开时先展示启动界面 打开设置,在SystemSeting下进行如下操作即可

  10. swiper + ts 类型报错

    swiper + ts 类型报错 "swiper": "^9.4.1" 版本号 原因 修改 tsconfig.json 文件下面的 moduleResoluti ...