
1. 项目概述与核心价值最近在给几台老旧的CentOS 7服务器做技术栈升级项目要求必须使用JDK 21的新特性。说实话在CentOS 7这种“经典”系统上安装最新的JDK就像给一台老爷车换装最新的V12发动机过程本身不复杂但中间的“水土不服”和“兼容性调校”才是真正的挑战。网上教程很多但大多只告诉你“下载、解压、配环境变量”三步走真照着做十有八九会遇到各种稀奇古怪的问题比如GLIBC版本不够、系统服务无法启动、甚至某些依赖库直接报错。这篇文章我就结合自己最近的实际操作把在CentOS 7上从零开始安装、配置、验证JDK 21的完整流程以及我踩过的坑和总结的避坑技巧毫无保留地分享出来。无论你是运维工程师、后端开发者还是需要在老旧生产环境部署新应用的技术负责人这篇内容都能帮你省下大量排查和折腾的时间。2. 环境准备与前置检查在动手安装之前盲目操作是最大的忌讳。CentOS 7默认的环境和JDK 21的要求之间存在一些“代沟”我们必须先摸清家底做好万全准备。2.1 系统环境确认首先我们需要确认当前系统的具体版本和架构。这决定了我们后续应该下载哪个版本的JDK安装包。# 查看系统版本和内核信息 cat /etc/redhat-release uname -m通常对于CentOS 7输出会是类似CentOS Linux release 7.9.2009 (Core)和x86_64。x86_64就是我们常说的64位系统这也是我们下载JDK时主要选择的架构。这里有一个关键点一定要确认是x86_64而不是i686或i386。后者是32位系统而Oracle官方从某个版本开始就不再提供32位的Linux JDK安装包了如果系统是32位整个安装计划就需要重新考虑。2.2 检查现有Java环境很多服务器上可能已经安装了OpenJDK 1.8或其他版本的Java。为了避免冲突我们需要先检查并决定如何处理它们。# 检查当前系统已安装的Java版本 java -version 2/dev/null || echo Java未安装或未在PATH中 # 检查通过yum安装的Java包 rpm -qa | grep -E \java|jdk|jre\ # 或者使用更精确的查询 yum list installed | grep -E \^java|^jdk|^jre\如果发现已经安装了旧版本的JDK比如OpenJDK 1.8你需要做一个决策保留并存如果你的一些老旧应用依赖特定版本的Java可以保留它们。后续通过配置环境变量让系统默认使用我们新安装的JDK 21。这是最稳妥的方式。彻底移除如果确定所有应用都可以或即将迁移到JDK 21可以考虑卸载旧版本以保持环境纯净。但生产环境务必谨慎建议先在测试环境验证所有应用的兼容性。注意直接使用yum remove java*是极其危险的操作它可能会卸载掉一些系统工具如javac可能被某些管理脚本间接依赖或其他应用的核心组件。正确的做法是根据上一步rpm -qa列出的具体包名选择性卸载。例如sudo yum remove java-1.8.0-openjdk-headless。2.3 关键依赖库检查这是CentOS 7安装高版本JDK最容易出问题的环节。JDK 21的某些组件特别是图形界面相关库即使你只用它跑无头服务可能依赖比CentOS 7默认版本更高的系统库。最典型的就是GLIBC。运行以下命令检查# 查看当前系统的glibc版本 ldd --version | head -1 # 或者 rpm -q glibcCentOS 7.9 自带的GLIBC版本通常是2.17。而JDK 21的构建环境可能基于更新的系统。虽然大部分情况下2.17是够用的但如果你下载的是某些特定构建版本如从某些Linux发行版仓库直接获取的可能会要求2.18或更高。如果版本不够后续运行java -version时可能会报错 “/lib64/libc.so.6: version \GLIBC_2.XX not found”。怎么办首选方案从Oracle官网或AdoptiumEclipse Temurin下载针对“通用Linux”的构建包通常是.tar.gz格式。这些包为了兼容性通常会链接到较低版本的GLIBC。备选方案如果必须使用某个依赖高版本GLIBC的JDK那么升级CentOS 7的GLIBC是极其危险的操作因为几乎整个系统都依赖它。强行升级极易导致系统崩溃。这种情况下建议考虑使用容器技术如Docker来隔离运行环境或者评估升级操作系统本身的可能性。除了GLIBC还应该确保一些基础开发工具的存在用于可能的调试或源码编译虽然安装JDK不需要# 安装常用的开发工具和库非必须但建议 sudo yum install -y wget tar gzip3. JDK 21安装包获取与验证准备好了系统环境接下来就是获取JDK 21安装包。这里我强烈推荐使用Eclipse Temurin原AdoptOpenJDK的发行版。原因有几个首先它是完全开源、免费的其次它提供了经过严格测试的、高质量的二进制包最后它的下载页面清晰提供了直接的文件链接非常适合脚本化安装。3.1 选择并下载安装包我们不从Oracle官网下载因为需要登录账户且许可协议对于生产环境可能更复杂。Temurin是更好的选择。访问 Eclipse Temurin Releases 。找到JDK 21选择Linux版本架构选择x64包类型选择JDK不是JRE格式强烈建议选择.tar.gz。为什么选.tar.gz而不是.rpm灵活性.tar.gz是压缩归档你可以解压到任何目录如/opt,/usr/local管理起来更灵活卸载也简单直接删除目录即可。兼容性避免了与系统包管理器yum的耦合不会因为安装JDK而影响系统其他包的依赖关系。多版本共存可以轻松地在同一台机器上安装多个JDK版本通过切换环境变量来使用不同版本。在服务器上我们可以直接用wget下载。首先在浏览器里找到正确的下载链接通常右键点击下载按钮选择“复制链接地址”。链接格式类似https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.213/OpenJDK21U-jdk_x64_linux_hotspot_21.0.2_13.tar.gz# 进入一个临时目录比如 /tmp cd /tmp # 使用 wget 下载将下面的URL替换成你从官网复制的实际链接 wget https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.213/OpenJDK21U-jdk_x64_linux_hotspot_21.0.2_13.tar.gz如果服务器无法访问GitHub可以先将安装包下载到本地再通过SFTP等工具上传到服务器。3.2 验证安装包完整性这是一个好习惯可以确保下载的文件没有损坏或被篡改。Temurin提供了SHA-256校验和文件。你需要下载同名的.sha256.txt文件。# 下载校验和文件 wget https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.213/OpenJDK21U-jdk_x64_linux_hotspot_21.0.2_13.tar.gz.sha256.txt # 计算下载的tar.gz文件的SHA256值 sha256sum OpenJDK21U-jdk_x64_linux_hotspot_21.0.2_13.tar.gz # 对比两个值是否一致 cat OpenJDK21U-jdk_x64_linux_hotspot_21.0.2_13.tar.gz.sha256.txt如果两个哈希值完全一致说明安装包完好无损。如果不一致请重新下载。4. 安装与目录规划安装过程其实就是解压和放置到合适的位置。目录规划很重要一个好的习惯能让后续的管理和维护轻松很多。4.1 创建标准化的安装目录在Linux系统中通常将第三方手动安装的软件放在/opt或/usr/local目录下。我个人的习惯是使用/usr/local/java因为这个路径比较直观也符合FHS文件系统层次结构标准的惯例。# 创建Java安装目录如果已有可以跳过 sudo mkdir -p /usr/local/java # 将下载的JDK压缩包移动到该目录或者直接在目标目录下载 sudo mv /tmp/OpenJDK21U-jdk_x64_linux_hotspot_21.0.2_13.tar.gz /usr/local/java/ cd /usr/local/java4.2 解压并建立版本化软链接解压安装包并使用软链接来管理版本这是非常专业且实用的技巧。# 解压压缩包 sudo tar -xzf OpenJDK21U-jdk_x64_linux_hotspot_21.0.2_13.tar.gz # 解压后会生成一个目录名称类似 jdk-21.0.213 # 查看解压出的目录名 ls -d jdk-*现在你有了一个具体的版本目录例如jdk-21.0.213。为了便于管理和将来可能的版本升级我们创建一个通用的软链接指向它。# 创建一个名为 jdk21 的软链接指向具体的版本目录 sudo ln -sfn jdk-21.0.213 jdk21这样做的巨大好处是环境变量固定你所有的配置环境变量、脚本都指向/usr/local/java/jdk21无需因版本号变化而修改。版本切换无缝未来如果需要升级到JDK 21.0.3你只需要解压新版本然后重新执行sudo ln -sfn jdk-21.0.310 jdk21所有指向jdk21的配置就自动切换到新版本了。回滚方便如果需要回退只需将软链接指回旧版本目录即可。现在JDK的实际安装路径是/usr/local/java/jdk-21.0.213而我们的逻辑使用路径是/usr/local/java/jdk21。5. 全局环境变量配置安装好JDK后需要让系统知道它的位置。配置环境变量有两种主要方式针对单个用户的~/.bashrc和针对所有用户的/etc/profile.d/。对于服务器上的Java环境我推荐使用后者因为这样所有登录的用户包括运行服务的系统用户如tomcat,jenkins都能使用统一的Java环境。5.1 创建全局环境变量脚本在/etc/profile.d/目录下创建脚本是CentOS/RHEL系统的标准做法系统在启动时会自动加载该目录下所有.sh脚本。# 使用vim或你喜欢的编辑器创建脚本 sudo vim /etc/profile.d/jdk21.sh在打开的文件中输入以下内容#!/bin/bash # Set JDK 21 Environment Variables export JAVA_HOME/usr/local/java/jdk21 export JRE_HOME$JAVA_HOME/jre export CLASSPATH.:$JAVA_HOME/lib:$JRE_HOME/lib export PATH$JAVA_HOME/bin:$PATH逐行解释JAVA_HOME指向JDK的安装根目录。很多Java应用和工具如Maven、Gradle、Tomcat都依赖这个变量。JRE_HOME指向JRE目录一些老式应用或脚本可能会用到。CLASSPATH定义Java类文件的查找路径。开头的.代表当前目录这样你可以在任意位置运行自己编译的.class文件。现代Java项目大多使用构建工具管理依赖这个变量作用已减弱但保留它是一个好习惯。PATH将$JAVA_HOME/bin添加到系统路径的最前面。这确保了当你在命令行输入java,javac等命令时系统会优先使用我们刚安装的JDK 21而不是系统可能自带的旧版本Java。保存并退出编辑器在vim中按Esc然后输入:wq回车。5.2 使环境变量立即生效并验证创建的脚本会在下次用户登录时自动生效。但我们不想重启服务器或重新登录可以手动source它。# 使环境变量在当前shell会话中立即生效 source /etc/profile.d/jdk21.sh # 验证环境变量是否设置正确 echo $JAVA_HOME echo $PATH | grep jdk现在进行最终的安装验证# 检查Java版本 java -version # 检查编译器版本 javac -version如果一切顺利你将看到类似下面的输出明确显示来自 “Eclipse Temurin” 的 “build 21.0.213”openjdk version \21.0.2\ 2024-01-16 OpenJDK Runtime Environment Temurin-21.0.213 (build 21.0.213) OpenJDK 64-Bit Server VM Temurin-21.0.213 (build 21.0.213, mixed mode, sharing)看到这个恭喜你JDK 21已经成功安装并配置为系统默认Java环境了。6. 高级配置与生产环境调优对于个人开发或测试到上一步已经足够了。但对于生产服务器我们还需要进行一些加固和优化确保环境稳定、安全、高效。6.1 配置替代版本管理alternatives虽然通过环境变量PATH可以控制默认Java但Linux提供了一个更系统级的工具alternatives替代方案来管理多个同类型软件。配置它可以让系统更规范地识别Java并且一些通过yum安装的软件包在查找Java时可能会依赖alternatives。# 安装alternatives配置如果之前有旧版本这里会将其覆盖 sudo alternatives --install /usr/bin/java java /usr/local/java/jdk21/bin/java 2100 sudo alternatives --install /usr/bin/javac javac /usr/local/java/jdk21/bin/javac 2100 sudo alternatives --install /usr/bin/jar jar /usr/local/java/jdk21/bin/jar 2100 # 可以继续添加其他常用命令如 javadoc, jshell, keytool 等参数解释--install 链接 名称 路径 优先级在系统命令链接池中注册一个替代项。链接在/usr/bin下创建的软链接名如java。名称管理组名称如javaalternatives通过这个名称来管理一组命令。路径实际可执行文件的绝对路径。优先级一个整数数字越大优先级越高。当有多个候选时系统会自动选择优先级最高的或允许你手动切换。这里设为2100远高于yum安装的OpenJDK 1.8优先级通常为18xx确保我们的JDK 21被默认选中。配置完成后你可以运行以下命令查看和管理# 查看java命令的当前选择 sudo alternatives --config java # 如果只有一个选项会直接显示。如果有多个会列出菜单让你选择。6.2 为系统服务用户配置环境如果你的Java应用是以系统服务通过systemd运行的或者是以tomcat、jenkins等特定用户运行的那么仅仅在/etc/profile.d/中设置环境变量可能还不够。因为systemd服务在启动时通常不会加载用户的shell配置文件。方法一在服务单元文件中直接定义这是最推荐的方式。编辑你的应用服务文件如myapp.service在[Service]部分添加Environment指令[Service] ... Environment\JAVA_HOME/usr/local/java/jdk21\ Environment\PATH/usr/local/java/jdk21/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin\ ...方法二使用全局环境文件创建或编辑/etc/environment这是一个系统级别的环境变量配置文件所有进程包括systemd服务都会读取。但注意它的格式是简单的KEYVAL每行一个不能使用变量扩展如$PATH。# 在 /etc/environment 中添加 JAVA_HOME/usr/local/java/jdk21修改后需要重启服务或整个系统才能生效。6.3 基础安全与性能调优可选安装完JDK后可以考虑做一些基础设置禁用不安全的TLS协议和加密套件编辑$JAVA_HOME/conf/security/java.security可以修改jdk.tls.disabledAlgorithms和jdk.certpath.disabledAlgorithms来禁用老旧的SSLv3、TLS 1.0/1.1以及弱加密算法。但这需要根据你的应用兼容性谨慎调整。设置默认的JVM编码为了避免中文乱码问题可以在启动应用时添加-Dfile.encodingUTF-8参数或者在环境变量中设置JAVA_TOOL_OPTIONS\-Dfile.encodingUTF-8\。但后者是全局设置可能影响所有Java应用需谨慎。配置jinfo和jstack等工具的使用确保运行Java进程的用户有权限使用这些调试工具。有时需要调整Linux内核参数如ptrace_scope或设置sudo规则。7. 常见问题排查与解决方案实录即使按照步骤操作在实际部署中也可能遇到问题。下面是我总结的几个典型问题及其解决方法。7.1 问题一执行java -version报错 “bash: java: command not found”可能原因与排查环境变量未生效执行source /etc/profile.d/jdk21.sh后只对当前shell生效。新开的终端窗口需要重新登录或手动source。确保脚本文件有可执行权限sudo chmod x /etc/profile.d/jdk21.sh。PATH设置错误检查echo $PATH看其中是否包含/usr/local/java/jdk21/bin。如果没有检查/etc/profile.d/jdk21.sh中PATH的赋值语句是否正确。软链接或目录不存在检查/usr/local/java/jdk21/bin/java这个文件是否存在。如果jdk21是一个损坏的软链接也会导致此问题。使用ls -l /usr/local/java/jdk21查看。解决方案重新加载配置文件source /etc/profile或重新登录服务器。检查并修正jdk21.sh脚本中的路径。使用alternatives配置后可以尝试直接使用/usr/bin/java -version测试。7.2 问题二执行java -version显示的还是旧版本如1.8可能原因与排查PATH顺序问题旧版本Java的路径如/usr/bin/java在新版本路径之前。执行which java和type -a java查看所有可用的java命令及其优先级。alternatives未正确配置或优先级低运行sudo alternatives --config java查看当前选择。如果列表中有多个确保选择了我们安装的JDK 21对应的条目。解决方案调整PATH变量确保$JAVA_HOME/bin在旧路径之前。在我们的jdk21.sh中使用PATH$JAVA_HOME/bin:$PATH已经做到了这一点。如果使用了alternatives确保我们的JDK 21条目优先级最高我们设置了2100。如果没有被选中可以在交互菜单中选择对应的编号或者用命令强制设置sudo alternatives --set java /usr/local/java/jdk21/bin/java。7.3 问题三运行Java应用时出现 “GLIBC_2.XX not found” 错误可能原因这是最棘手的问题之一。意味着你下载的JDK二进制包是在比当前CentOS 7的GLIBC2.17更新的系统上编译的。解决方案换源重新下载一个明确支持GLIBC 2.17的JDK包。Eclipse Temurin的通用Linux.tar.gz包通常是兼容的。如果你是从其他渠道如某些Linux发行版的特定包下载的请换回Temurin的通用包。检查包类型确保你下载的是 for “Linux” 而不是 for “Alpine Linux” 或 “Linux musl”。后者是针对不同C库的不兼容。终极方案如果应用必须使用某个特定的、依赖高GLIBC的JDK构建那么考虑在Docker容器中运行该应用。创建一个基于较新Linux发行版如Ubuntu 22.04, CentOS Stream 9的Docker镜像在里面安装JDK 21和你的应用。这是隔离环境依赖的最佳实践。7.4 问题四系统服务如Tomcat无法启动提示找不到Java可能原因系统服务由systemd管理在启动时没有加载我们设置的环境变量JAVA_HOME或PATH。排查与解决检查服务单元文件sudo systemctl cat your-service-name。查看[Service]部分是否有Environment或EnvironmentFile指令来设置Java路径。在服务文件中显式设置如上文6.2节所述在服务的.service文件中添加Environment\JAVA_HOME/usr/local/java/jdk21\。使用全局配置在/etc/environment中设置JAVA_HOME但这会影响所有用户和进程。检查服务运行用户确保服务运行的用户如tomcat有权限读取/usr/local/java/jdk21目录及其下的文件。可以使用sudo -u tomcat ls /usr/local/java/jdk21/bin/java来测试。7.5 问题五安装后内存占用异常或性能不佳可能原因JDK 21的默认JVM参数可能不适合你的服务器配置尤其是内存较小的机器。初步调优建议检查默认参数运行java -XX:PrintFlagsFinal -version | grep -i heapsize可以查看默认的堆内存初始值InitialHeapSize和最大值MaxHeapSize。根据机器配置调整对于生产环境通常需要根据应用实际需求和机器内存显式设置JVM堆参数。例如在一台4GB内存的服务器上运行一个微服务可以设置-Xms512m -Xmx2g初始堆512MB最大堆2GB。这需要在启动应用的脚本或JAVA_OPTS中指定。选择适合的GC算法JDK 21默认的G1垃圾回收器对大多数应用表现良好。但对于低延迟要求的应用可以评估ZGC或Shenandoah。这需要更深入的测试和调优。8. 安装后的验证与最佳实践安装配置完成后不要以为就万事大吉了。进行全面的验证和建立维护规范才能保证环境的长期稳定。8.1 编写一个简单的测试程序创建一个最简单的Java程序验证编译和运行环境。cd /tmp cat HelloJDK21.java EOF public class HelloJDK21 { public static void main(String[] args) { // 使用JDK 21的文本块特性如果版本支持 String message Hello from JDK 21! Running on: %s Java Version: %s .formatted(System.getProperty(\os.name\), System.getProperty(\java.version\)); System.out.println(message); } } EOF # 编译 javac HelloJDK21.java # 运行 java HelloJDK21如果程序能成功运行并输出系统信息和Java版本说明JDK环境完全正常工作甚至能使用JDK 21的新语法特性如文本块。8.2 建立版本管理与回滚机制这是运维中的黄金法则。我们之前使用软链接jdk21已经为版本管理打下了基础。建议建立一个简单的记录文件sudo tee /usr/local/java/README.md EOF # JDK 安装目录管理 - 当前活跃版本通过软链接 jdk21 指向。 - 安装新版本步骤 1. 下载新版本tar.gz包到此目录。 2. 解压tar -xzf 新包名.tar.gz 3. 测试新版本新目录/bin/java -version 4. 切换软链接sudo ln -sfn 新目录名 jdk21 5. 验证java -version 6. 可选重启依赖Java的服务。 - 回滚将软链接重新指向旧版本目录即可。 EOF8.3 监控与日志对于生产环境建议将Java的版本信息纳入系统监控。可以在启动应用时将java -version的输出记录到应用日志或特定的系统信息文件中。也可以使用配置管理工具如Ansible来定期检查所有服务器上的Java版本是否一致。最后我个人习惯在重要的服务器上在/etc/motd登录提示信息或一个专门的$HOME/server.info文件中记录关键软件版本包括Java版本这样每次登录都能一目了然。一个简单的命令就可以实现java -version 21 | grep \version\ | tee -a /etc/motd需要root权限。