Skip to content

JDK 安装与多版本切换 ​

生产机器上同时存在 3 个 JDK 版本是常态:跑业务用 17、编译老项目用 8、某个中间件自带一个。最忌讳的是把 JAVA_HOME 写死到具体版本号目录,升级时全线崩。

一、tar 包安装(推荐) ​

发行版包管理器装的 JDK 会往 /usr/lib/jvm 塞一堆软链,且版本更新不可控。手工解压最干净。

bash
mkdir -p /opt/java && cd /opt/java
tar zxf jdk-17.0.11_linux-x64_bin.tar.gz
tar zxf jdk-8u421-linux-x64.tar.gz

ls -1 /opt/java

输出:

text
jdk1.8.0_421
jdk-17.0.11

解释:解压到哪不重要,重要的是统一放一个父目录,后面用软链切换。/opt 是第三方软件的规范位置,不跟系统包管理器抢 /usr。

二、用软链做版本解耦 ​

bash
ln -sfn /opt/java/jdk-17.0.11 /opt/java/current

然后所有地方只引用 /opt/java/current:

bash
# /etc/profile.d/java.sh
export JAVA_HOME=/opt/java/current
export PATH=$JAVA_HOME/bin:$PATH
bash
source /etc/profile.d/java.sh
java -version

输出:

text
openjdk version "17.0.11" 2024-04-16 LTS
OpenJDK Runtime Environment (build 17.0.11+7-LTS-207)
OpenJDK 64-Bit Server VM (build 17.0.11+7-LTS-207, mixed mode, sharing)

解释:换版本只需 ln -sfn /opt/java/jdk1.8.0_421 /opt/java/current,不用改任何脚本和 systemd 文件。这是本章最重要的一条约定。

source 只影响当前 shell

source /etc/profile.d/java.sh 改不了已经启动的进程,也不影响别的 SSH 会话。systemd 服务读不到 /etc/profile,必须在 unit 里显式写 Environment=(见"服务托管"一节)。

三、给单个应用固定版本 ​

不要让应用继承全局 JAVA_HOME——全局一改它就跟着变。

ini
# /etc/systemd/system/order.service 片段
[Service]
Environment=JAVA_HOME=/opt/java/jdk-17.0.11
ExecStart=/opt/java/jdk-17.0.11/bin/java -jar /opt/app/current/app.jar

解释:显式写全路径最保险。Environment= 只给这个服务,不影响别人。

四、alternatives 方式(RHEL 系) ​

适合"系统级默认版本"的切换,比如 javac 给命令行用:

bash
alternatives --install /usr/bin/java java /opt/java/jdk-17.0.11/bin/java 1700
alternatives --install /usr/bin/java java /opt/java/jdk1.8.0_421/bin/java 1800
alternatives --config java

输出:

text
  Selection    Path                                Priority   Status
------------------------------------------------------------
* 1            /opt/java/jdk-17.0.11/bin/java      1700       auto mode
  2            /opt/java/jdk1.8.0_421/bin/java     1800       auto mode

解释:优先级数字大的自动胜出,所以 JDK 8 反而成了默认——这是个常见的坑,命名优先级时要按"越大越新"的直觉反着留意。--config 是交互式选择,脚本里别用。

五、验证 JAVA_HOME 到底生效在哪 ​

bash
echo $JAVA_HOME
readlink -f "$(which java)"
java -XshowSettings:properties -version 2>&1 | grep -E 'java.home|java.version'

输出:

text
/opt/java/current
/opt/java/jdk-17.0.11/bin/java
    java.home = /opt/java/jdk-17.0.11
    java.version = 17.0.11

解释:三者不一致就是有问题——which java 命中的可能是 /usr/bin/java(系统包管理器装的),而不是你 PATH 里的那个。这时检查 echo $PATH 顺序,或直接 hash -r 清掉 shell 的命令路径缓存。

六、JDK 版本选择速查 ​

版本状态建议
8商用授权受限(Oracle),开源侧用 Temurin存量项目继续用,新项目别选
11LTS,支持到 2032(各厂商不同)老项目升级的稳妥中间档
17LTS当前主流,Spring Boot 3 的最低要求
21LTS虚拟线程值得为它升级
25+非 LTS只在能持续跟进的短周期项目上用

换发行版别忘 GC 默认值变了

JDK 8→11 默认仍是 Parallel GC;11 起 G1 成为默认;17 之后分Region 策略和停顿目标实现都有变化。同一段代码换 JDK 后 GC 日志形态会变,别以为"参数没改行为就不变"。