1. 项目缘起:为什么在CentOS 7上安装JDK 21是个“技术活”?
最近在给一个老项目做技术栈升级,后端服务需要从JDK 11迁移到JDK 21,以用上虚拟线程、分代ZGC这些新特性来提升性能。服务器环境是几台跑了好几年的CentOS 7,这就引出了一个看似简单、实则暗藏玄机的问题:如何在CentOS 7上顺利安装并配置JDK 21?你可能觉得,不就是下载、解压、配环境变量吗?但实际操作下来,从系统兼容性检查、包管理器选择、到后续的版本管理和服务集成,每一步都有值得细说的门道。特别是对于CentOS 7这样一个已经停止主流维护、但仍在生产环境广泛使用的系统,直接照搬Ubuntu或新版本CentOS的教程,大概率会踩坑。这篇文章,我就结合自己的实操经历,把在CentOS 7上部署JDK 21的完整流程、背后的原理,以及那些容易忽略的细节和避坑点,给你从头到尾捋清楚。
2. 环境审视与前期准备:你的CentOS 7真的准备好了吗?
在动手下载任何安装包之前,对现有系统环境进行一次彻底的“体检”是至关重要的。这能帮你提前规避大量因系统版本、架构或依赖缺失导致的问题。
2.1 确认系统架构与内核版本
首先,通过终端连接你的CentOS 7服务器。我们需要确认几个关键信息:
系统位数与架构:运行
uname -m命令。对于绝大多数云服务器和物理机,你会看到x86_64,这代表64位系统,也是我们安装JDK的前提。如果显示i386或i686,则是32位系统,而Oracle官方从JDK 9以后就不再提供32位Linux的通用版本了,这种情况下你需要寻找其他替代方案或考虑升级系统。内核版本与系统信息:运行
cat /etc/redhat-release和uname -r。CentOS 7的版本号(如7.6、7.9)和内核版本(如3.10.0-1160.el7.x86_64)决定了系统的基础库版本。虽然JDK 21对Linux内核的要求并不苛刻(官方建议GLIBC 2.17+),但确保系统相对较新(建议CentOS 7.6及以上)可以减少潜在的库冲突。
2.2 清理潜在的旧版本JDK
很多服务器上可能已经安装了OpenJDK 1.8或更早的版本。为了避免环境变量冲突和误用,最好先进行排查和清理。
检查已安装的Java:
java -version which java如果显示了版本信息,记下它的路径(通常是
/usr/bin/java)。查找并移除旧版JDK/RPM包:
- 对于通过yum安装的OpenJDK,可以使用
rpm -qa | grep -i jdk或rpm -qa | grep -i java来列出所有相关的RPM包。 - 如果你确定要移除它们(请确保没有关键服务依赖旧版Java),可以使用
sudo yum remove [package-name]进行卸载。例如,sudo yum remove java-1.8.0-openjdk。 - 重要提示:如果服务器上有运行中的Java服务(如Tomcat、Jenkins),务必先停止这些服务再进行卸载操作,否则可能导致服务异常。
- 对于通过yum安装的OpenJDK,可以使用
手动安装版本的清理:如果之前是通过下载tar.gz包手动安装的,你需要找到其安装目录(例如
/usr/local/java/jdk1.8.0_301)并将其整个目录删除,同时清理~/.bashrc或/etc/profile中相关的环境变量设置。
2.3 安装基础依赖工具
为了后续步骤顺利进行,确保以下工具已安装:
sudo yum install -y wget tar gzipwget用于从网络下载JDK安装包。tar和gzip用于解压下载的压缩包。
3. 获取JDK 21:官方与替代源的选择策略
目前获取JDK 21主要有两个官方渠道:Oracle JDK和OpenJDK。对于生产环境,选择哪一个需要仔细权衡。
3.1 Oracle JDK vs. OpenJDK:许可证与功能的权衡
- Oracle JDK:这是Oracle公司提供的发行版。从JDK 17开始,Oracle对其采用了新的“NFTC(No-Fee Terms and Conditions)”许可证,允许免费用于生产环境。它包含了一些OpenJDK没有的、Oracle专有的商业特性(如Java Flight Recorder, Java Mission Control的完整功能)。如果你需要这些高级监控和诊断工具,或者企业法务对许可证有明确要求,可以选择Oracle JDK。
- OpenJDK:这是Java平台的开源参考实现。由Oracle和OpenJDK社区共同维护。我们常说的Adoptium(原AdoptOpenJDK)、Amazon Corretto、Azul Zulu等都是基于OpenJDK源码构建的发行版,它们完全免费且通常提供了长期支持(LTS)版本。对于绝大多数应用场景,OpenJDK发行版是更通用、更省心的选择。
我的建议:对于CentOS 7生产服务器,我优先推荐使用Eclipse Temurin(由Adoptium项目提供)或Amazon Corretto。它们提供了预构建的、经过良好测试的二进制包,并且有明确的支持周期,省去了自己从源码编译的麻烦。
3.2 实操下载:以Eclipse Temurin为例
这里我演示从Adoptium(Eclipse Temurin)下载JDK 21 LTS版本。
- 访问 Adoptium Temurin Releases 页面。
- 在过滤器中选择:Version:
21, OS:Linux, Architecture:x64, Package Type:JDK, Image Type:JRE还是JDK?这里我们选择完整的JDK。 - 你会看到一个下载链接,例如
https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.3%2B9/OpenJDK21U-jdk_x64_linux_hotspot_21.0.3_9.tar.gz。链接中的版本号可能会更新,请以页面最新为准。 - 在服务器上,使用wget命令下载(请替换为实际的下载链接):
cd /usr/local/src sudo wget https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.3%2B9/OpenJDK21U-jdk_x64_linux_hotspot_21.0.3_9.tar.gz注意:如果服务器无法直接访问GitHub,下载速度很慢,可以考虑先将安装包下载到本地,再通过SCP或SFTP工具上传到服务器
/usr/local/src目录。
4. 安装与配置:不仅仅是解压那么简单
下载完成后,我们进入核心的安装和配置环节。这一步的目标是让JDK可以被系统全局调用,并且配置得当,为后续应用运行打好基础。
4.1 解压与目录规划
通常,我们将第三方软件安装在/usr/local或/opt目录下。这里我选择/usr/local/java,这个目录结构比较清晰。
# 创建Java安装目录 sudo mkdir -p /usr/local/java # 解压下载的JDK压缩包到该目录 sudo tar -xzf OpenJDK21U-jdk_x64_linux_hotspot_21.0.3_9.tar.gz -C /usr/local/java/ # 查看解压后的目录名 ls /usr/local/java/ # 你应该会看到一个类似 `jdk-21.0.3+9` 的目录解压后,你得到了一个包含完整JDK的目录。为了便于管理,我习惯创建一个软链接,指向当前使用的JDK版本。
# 进入目录 cd /usr/local/java # 创建软链接 ‘current’,指向刚解压的JDK目录 sudo ln -s jdk-21.0.3+9 current这样,以后无论环境变量还是应用配置,都可以指向/usr/local/java/current。当需要升级JDK时,只需解压新版本,更改软链接指向即可,实现了无缝切换。
4.2 配置全局环境变量
为了让所有用户都能方便地使用java,javac等命令,我们需要修改系统级的环境变量配置文件。
打开配置文件:
sudo vim /etc/profile或者使用
sudo nano /etc/profile。在文件末尾添加以下内容:
# JDK 21 Environment Configuration export JAVA_HOME=/usr/local/java/current export JRE_HOME=$JAVA_HOME/jre export CLASSPATH=.:$JAVA_HOME/lib:$JRE_HOME/lib export PATH=$JAVA_HOME/bin:$PATHJAVA_HOME:许多Java应用(如Tomcat, Maven, Gradle)和脚本依赖这个变量来定位Java安装根目录。- 将
$JAVA_HOME/bin添加到PATH的最前面,确保系统优先使用我们新安装的JDK 21。
保存并退出编辑器。
使配置立即生效:
source /etc/profile这个命令只对当前终端会话生效。新打开的终端或者通过SSH新建的连接,会自动读取新的配置。
4.3 验证安装
现在,让我们验证安装是否成功。
# 检查java版本 java -version如果配置正确,你会看到类似下面的输出:
openjdk version "21.0.3" 2024-04-16 LTS OpenJDK Runtime Environment Temurin-21.0.3+9 (build 21.0.3+9-LTS) OpenJDK 64-Bit Server VM Temurin-21.0.3+9 (build 21.0.3+9-LTS, mixed mode, sharing)# 检查javac编译器版本 javac -version输出应为javac 21.0.3。
# 检查JAVA_HOME变量 echo $JAVA_HOME输出应为/usr/local/java/current。
如果以上命令都返回了预期的JDK 21信息,恭喜你,基础安装已经成功了。
5. 进阶配置与生产环境调优
安装成功只是第一步。要让JDK 21在CentOS 7生产环境中稳定、高效地运行,还需要进行一些额外的配置。
5.1 配置备用字符编码(解决中文乱码)
CentOS 7 minimal安装默认可能不包含完整的中文字体包,这可能导致Java应用(特别是那些有图形界面或生成PDF报告的应用)输出中文时显示为方框(乱码)。
安装字体包:
sudo yum install -y fontconfig dejavu-sans-fontsdejavu-sans-fonts是一个高质量、开源的字体家族,通常能解决大部分字符显示问题。在Java应用的启动脚本中,可以显式指定字符集。例如,在启动Spring Boot的Jar包时:
java -Dfile.encoding=UTF-8 -jar your-application.jar
5.2 调整系统文件描述符与用户进程限制
高并发的Java应用(如Netty服务、Web服务器)可能会需要打开大量的网络连接(Socket),每个连接都消耗一个文件描述符。CentOS 7的默认限制可能不够。
查看当前限制:
ulimit -n # 查看单个进程可打开的文件数 ulimit -u # 查看用户可创建的最大进程数全局修改限制,编辑
/etc/security/limits.conf,在文件末尾添加:* soft nofile 65535 * hard nofile 65535 * soft nproc 65535 * hard nproc 65535这里
*代表所有用户,soft是软限制,hard是硬限制,nofile是文件描述符数量,nproc是进程数。修改后需要重启服务器或重新登录用户会话才能生效。
5.3 JDK 21特定参数与垃圾回收器选择
JDK 21引入了分代ZGC(Z Garbage Collector),这是一个低延迟的垃圾回收器。如果你的应用对延迟非常敏感(例如金融交易系统、实时游戏服务器),可以尝试启用它。
在应用启动参数中添加:
java -XX:+UseZGC -jar your-app.jar对于JDK 21,ZGC默认就是分代的,提供了更好的吞吐量。你可以通过-XX:ZGenerational显式控制,但在21版本中,-XX:+UseZGC默认就启用了分代模式。
参数调优建议:垃圾回收器的选择没有银弹。对于大多数Web应用,G1 GC(-XX:+UseG1GC)仍然是平衡吞吐量和延迟的稳健选择。建议先在测试环境使用JMeter等工具进行压测,同时通过-Xlog:gc*参数输出GC日志,使用GC分析工具(如GCeasy)来观察和调整堆大小(-Xms,-Xmx)及GC参数。
6. 集成到系统服务(以Spring Boot为例)
在生产环境,我们通常将Java应用作为系统服务(systemd service)来管理,实现开机自启、故障重启、日志集中管理。
假设我们有一个打包好的Spring Boot应用myapp.jar,存放在/opt/myapp目录。
创建服务配置文件:
sudo vim /etc/systemd/system/myapp.service写入以下配置内容:
[Unit] Description=My Spring Boot Application After=network.target syslog.target [Service] Type=simple User=appuser # 建议创建一个专门的系统用户来运行应用,而非root WorkingDirectory=/opt/myapp ExecStart=/usr/local/java/current/bin/java -Xms512m -Xmx1024m -jar /opt/myapp/myapp.jar SuccessExitStatus=143 TimeoutStopSec=30 Restart=on-failure RestartSec=10 [Install] WantedBy=multi-user.targetUser:指定运行服务的用户,提升安全性。ExecStart:这里明确使用了我们安装的JDK 21的完整路径来启动应用。Restart=on-failure:当进程异常退出时,自动重启。-Xms和-Xmx:设置了JVM堆内存的初始大小和最大大小,请根据你的应用实际需求调整。
重新加载systemd配置,启动并启用服务:
sudo systemctl daemon-reload sudo systemctl start myapp sudo systemctl enable myapp # 设置开机自启 sudo systemctl status myapp # 查看服务状态查看应用日志:
sudo journalctl -u myapp -f
通过systemd管理,你的Java应用就具备了生产级服务的基本管理能力。
7. 常见问题排查与解决方案
即使在按照步骤操作后,你仍可能遇到一些问题。这里列举几个典型场景。
7.1 执行java -version显示旧版本
问题:配置了环境变量后,java -version仍然显示系统自带的OpenJDK 1.8。
原因与解决:这通常是因为/usr/bin/java这个软链接仍然指向旧版本。which java命令会显示/usr/bin/java,而PATH中/usr/bin的优先级可能高于/usr/local/java/current/bin(取决于你在/etc/profile中设置PATH的顺序)。
- 检查PATH顺序:
echo $PATH,确保/usr/local/java/current/bin在/usr/bin前面。 - 如果PATH顺序正确,可能是旧版的RPM包安装的Java覆盖了命令。你可以选择:
- 方案A(推荐):使用
alternatives命令来管理系统中的多个Java版本。# 将新JDK加入alternatives系统 sudo alternatives --install /usr/bin/java java /usr/local/java/current/bin/java 3000 sudo alternatives --install /usr/bin/javac javac /usr/local/java/current/bin/javac 3000 # 交互式选择默认版本 sudo alternatives --config java sudo alternatives --config javac - 方案B:直接移除旧版的java命令软链接,并创建新的(有一定风险,如果其他软件依赖特定版本):
sudo rm /usr/bin/java sudo ln -s /usr/local/java/current/bin/java /usr/bin/java
- 方案A(推荐):使用
7.2 应用启动时报GLIBC_2.XX未找到
问题:在非常老的CentOS 7系统上,启动JDK 21时可能报错,提示需要更高版本的GLIBC。
原因:JDK 21二进制编译时链接的GNU C库(glibc)版本比当前系统的高。
解决:
- 首先尝试更新系统到最新:
sudo yum update。这通常会升级glibc。 - 如果更新后仍不行,说明你的系统版本实在太老。生产环境强烈建议将系统升级到CentOS 7.9或考虑迁移到更新的操作系统(如Rocky Linux 8/9)。不推荐手动编译升级glibc,这极易导致系统不稳定甚至崩溃。
7.3 通过yum安装的软件(如Jenkins)仍使用旧版Java
问题:像Jenkins、Tomcat等通过yum安装的软件,可能有自己的服务启动脚本,里面写死了Java路径(例如/usr/lib/jvm/java-1.8.0-openjdk)。
解决:需要修改对应服务的配置文件。
- 对于Jenkins,编辑
/etc/sysconfig/jenkins,找到JENKINS_JAVA_CMD或JAVA_HOME参数,将其修改为/usr/local/java/current。 - 对于Tomcat(通过yum安装),编辑
/etc/tomcat/tomcat.conf或/usr/libexec/tomcat/server等启动脚本,设置JAVA_HOME。 修改后,记得重启对应的服务。
8. 维护与升级:建立可持续的Java环境管理
安装一次不是终点。考虑到安全补丁和性能改进,我们需要规划如何管理JDK的版本。
使用版本管理目录结构:正如我们之前做的,使用软链接
current指向具体版本目录。当需要升级到JDK 21.0.4时,流程如下:# 1. 下载并解压新版本到 /usr/local/java/jdk-21.0.4+10 # 2. 停止所有依赖Java的服务 sudo systemctl stop myapp jenkins tomcat # 3. 切换软链接 cd /usr/local/java sudo rm -f current sudo ln -s jdk-21.0.4+10 current # 4. 重启服务 sudo systemctl start myapp jenkins tomcat # 5. 验证 java -version考虑使用SDKMAN!(适用于开发/测试环境):如果你在CentOS 7上做开发,可以安装SDKMAN!来管理多个JDK版本。它允许你轻松地安装、切换、删除不同版本。但请注意,在生产服务器上,我更倾向于手动管理,以获得更精确的控制和更少的依赖。
监控与日志:确保应用和JVM的日志被妥善收集(例如发送到ELK或Graylog)。监控JVM的堆内存使用情况、GC频率和时长(可以通过JMX或
jstat工具),这些是判断是否需要调整JVM参数或升级硬件资源的重要依据。
整个流程走下来,在CentOS 7上安装JDK 21远不止一个解压命令。它涉及到系统环境的清理、发行版的选择、目录的规划、环境变量的持久化配置、与现有系统服务的集成,以及后续的版本管理和监控。尤其是在一个相对老旧的系统上引入新的运行时,提前做好兼容性检查和问题预案,是保证部署顺利的关键。希望这份详细的指南,能帮你避开我踩过的那些坑,一次部署成功。