现在的 MacOS 都不自带 JDK 了,如果你在未安装 JDK 的 MacOS 中执行 Java 命令会出现如下提示:
AigeStudio@aige$ java -version
No Java runtime present, requesting install.
然后 MacOS 会提示你 JDK 未安装:
点击更多信息的话就会去到 Oracle 的 JDK 下载页让你下载安装,在稍微早一点的 MacOS 版本中点击更多信息会让你跳转至 Apple 的 JDK 6 下载页,不管怎么个方式,MacOS 就是要你自己去安装 JDK,自行下载安装包安装 JDK 虽然可行,但是 JDK 的包并非是 app 而是 pkg 的形式,管理、升级和卸载起来都极不方便,因此这里爱哥是很不推荐下载安装包安装 JDK 的,相较而言,使用 brew 提供自动安装和卸载的功能,管理起来也比自行安装方便轻松。如果你还没用过 brew 的话可以参阅 MacOS 安装 brew 并配置 cask。
使用 brew 安装 JDK 也非常简单,如果你只是安装最新的 JDK,那么直接执行下述命令即可:
AigeStudio@aige$ brew cask install java
当然很多时候我们开发环境并不一定只局限于最新版的 JDK,还需要一些低版本的 JDK,如果使用 brew 安装其他版本的 JDK 还需要使用 “homebrew-cask-versions”,该命令行工具用作于安装应用的历史版本,如果你未曾使用过它那么则需要先使用下述命令配置:
AigeStudio@aige$ brew tap caskroom/versions
然后执行 brew 的 search 命令看看有哪些 JDK 版本可供安装:
AigeStudio@aige$ brew search java
这里爱哥已经安装了 JDK 的最新版 12 以及 8 和 6,可以看到执行搜索命令后会出现已安装的状态标识(该功能实现参阅 巧用 iTerm2 & zsh & oh-my-zsh 打造炫酷的 MacOS 终端环境)系列文章:
安装完所有你需要的 JDK 版本后执行下述命令就可以查看所有已安装的 JDK 版本路径地址:
AigeStudio@aige$ /usr/libexec/java_home -V
比如这里爱哥安装了三个版本的 JDK (其中 JDK6 区分了 32bit 和 64bit 版本):
得到每个不同的 JDK 路径后我们就可以着手在这些 JDK 之间进行切换,在默认情况下 MacOS 中 Java 使用的是最新的 JDK 版本,可以通过命令:
AigeStudio@aige$ java -version
查看,比如这里爱哥使用的最新版本就是 Open JDK 12:
我们可以通过设置系统的环境变量 JAVA_HOME 来在不同的 JDK 版本之间切换,最简单的方式就是通过 “export” 命令手动修改它的值:
AigeStudio@aige$ export JAVA_HOME=/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
不过每次都输入这么一长串命令显得太过繁琐不够智能,我们可以在 shell 的配置文件(如果是 bash 则在 ~/.bash_profile;如果是 zsh,则在 ~/.zshrc )中以指定 alias 的方式简化切换命令:
# JDK 6、JDK 8、JDK 12 的 export 命令
export JDK6_HOME="/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home"
export JDK8_HOME="/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home"
export JDK12_HOME="/Library/Java/JavaVirtualMachines/openjdk-12.0.1.jdk/Contents/Home"
# alias 命令链接到 export 命令
alias jdk6="export JAVA_HOME=$JDK6_HOME"
alias jdk8="export JAVA_HOME=$JDK8_HOME"
alias jdk12="export JAVA_HOME=$JDK12_HOME"
修改完 Shell 配置文件后保存并执行 source 命令实时更新配置文件:
AigeStudio@aige$ source 配置文件路径(如果是bash则为~/.bash_profile;如果是zsh,则为~/.zshrc)
最后我们就可以在 Shell 中使用 jdk6、jdk8、jdk12 命令切换不同的 JDK 版本了。
使用 export & alias 的方式管理 JDK 固然没问题,但是当我们遇到复杂的场景时这种方式就显得不中用了。比如我们又很多不同的 Java 项目,而这些 Java 项目之间又互相依赖,并且这些 Java 项目都不是使用统一的 JDK 版本。如果我们使用 export & alias 的方式切换 JDK,那么就有可能会导致一些项目可以编译成功一些不能。一种更好的思路是限制 export & alias 的作用范围,即可以将其对 JDK 环境变量的设置作用于某个具体的项目,即作用到具体的目录。这个思路虽好,但是使用 export & alias 的方式实现起来就比较困难。这里爱哥给大家推荐 JEnv 这个小工具,它可以帮我们更好地管理 & 切换不同版本的 JDK。
JEnv 的安装很简单,你可以直接参考其官方网站。JEnv 目前支持 Linux 和 MacOS 两种操作系统,在 MacOS 下你可以直接使用 brew 进行安装(注:如果你还没用过 brew 的话可以参阅 MacOS 安装 brew 并配置 cask):
AigeStudio@aige$ brew install jenv
然后配置 Shell 添加如下配置参数
# 如果你是用的 bash 则执行下述命令
AigeStudio@aige$ echo 'export PATH="$HOME/.jenv/bin:$PATH"' >> ~/.bash_profile
AigeStudio@aige$ echo 'eval "$(jenv init -)"' >> ~/.bash_profile
# 如果你是用的 zsh 则执行下述命令
AigeStudio@aige$ echo 'export PATH="$HOME/.jenv/bin:$PATH"' >> ~/.zshrc
AigeStudio@aige$ echo 'eval "$(jenv init -)"' >> ~/.zshrc
最后我们使用上述使用到的 /usr/libexec/java_home -V
命令罗列出已经安装的 JDK 路径:
AigeStudio@aige$ /usr/libexec/java_home -V
Matching Java Virtual Machines (4):
12.0.1, x86_64: "OpenJDK 12.0.1" /Library/Java/JavaVirtualMachines/openjdk-12.0.1.jdk/Contents/Home
1.8.0_212, x86_64: "AdoptOpenJDK 8" /Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home
1.6.0_65-b14-468, x86_64: "Java SE 6" /Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
1.6.0_65-b14-468, i386: "Java SE 6" /Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
再使用 jenv add 命令挨个将上述路径添加即可:
AigeStudio@aige$ jenv add /Library/Java/JavaVirtualMachines/openjdk-12.0.1.jdk/Contents/Home
AigeStudio@aige$ jenv add /Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home
AigeStudio@aige$ jenv add /Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
完成上述配置后使用 JEnv 的 versions 命令查看已经被添加至 JEnv 管理的 JDK 版本:
AigeStudio@aige$ jenv versions
system
1.6
1.6.0.65
1.8
1.8.0.212
12.0
* 12.0.1 (set by /Users/aige/.jenv/version)
openjdk64-1.8.0.212
openjdk64-12.0.1
oracle64-1.6.0.65
如果看到我们添加的 JDK 6、JDK 8 和 JDK 12 被添加了则表明配置成功。这里需要注意的是,JEnv 会读取 JDK 的不同别名来作为显示。比如上面命令行中罗列出的 1.8、1.8.0.212 以及 openjdk64-1.8.0.212 其实指代的都是 JDK 8。而版本号左边带星号 “*” 的则表示当前执行 Java 命令后会使用到的 JDK 版本。比如上述命令行中 12.0.1 左边有星号,这时我们执行一个 java version 命令:
AigeStudio@aige$ java -version
openjdk version "12.0.1" 2019-04-16
OpenJDK Runtime Environment (build 12.0.1+12)
OpenJDK 64-Bit Server VM (build 12.0.1+12, mixed mode, sharing)
显示的就会是 JDK 12 的版本。
JEnv 的精髓是 shell、local 和 global 三个参数命令。shell 用于设置终端窗口生命周期内使用的 JDK 版本;local 用于设置当前目录下使用的 JDK 版本;而 global 用于设置全局使用的 JDK 版本。这三个命令的使用方式都一样:
AigeStudio@aige$ jenv shell/local/global 1.6
上述命令最后的 “1.6” 即我们在 JEnv 中设置的不同 JDK 版本的别名。这里如果我们想在当前终端窗口中使用 JDK 8,我们只需执行:
AigeStudio@aige$ jenv shell 1.8
此时我们再执行 java version 命令就会显示使用的是 JDK 8:
AigeStudio@aige$ jenv shell 1.8
AigeStudio@aige$ java -version
openjdk version "1.8.0_212"
OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_212-b04)
OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.212-b04, mixed mode)
shell 命令设置的 JDK 是终端窗口生命周期内有效的,即你一旦退出终端再次进入则会失效。而 local 命令则可以让你在某个目录下执行某个具体版本的 JDK:
local 命令不像 shell 那样有生命周期,一旦在某个目录下使用 local 设置了 JDK 版本,就会在该目录下生成一个 “.java-version” 文件,该文件中记录了当前目录所使用的 JDK 版本,只要你不删除该文件,则设置会一直有效。最后的 global 命令就不说了很好理解。
shell、local 和 global 命令几乎就是 JEnv 的全部,其它的一些小功能不太常用,你可以参考其官方文档或者直接查看 jenv 的命令帮助:
AigeStudio@aige$ jenv
jenv 0.5.2
Usage: jenv <command> [<args>]
Some useful jenv commands are:
commands List all available jenv commands
local Set or show the local application-specific Java version
global Set or show the global Java version
shell Set or show the shell-specific Java version
rehash Rehash jenv shims (run this after installing executables)
version Show the current Java version and its origin
versions List all Java versions available to jenv
which Display the full path to an executable
whence List all Java versions that contain the given executable
See jenv help <command> for information on a specific command.
For full documentation, see: https://github.com/hikage/jenv#readme