macOS上使用多个JDK版本

虽然Oracle依然免费提供最新版本的Java JDK,例如,当前JDK 14可以从Oracle官网下载。但是Oracle对于旧版本JDK,特别是当前企业大量使用的成熟版本的JDK 8是需要收费账号才可以下载使用。

备注

使用Oracle官方提供的JDK软件安装包安装JDK之后,如果要切换到社区维护的不同JDK版本,则需要先卸载Oracle Java。不过卸载方法有些复杂。我以前的一些实践记录 在Mac OS X上安装Java多个版本

开源的OpenJDK维护了不同版本的JDK,也包括了JDK 8。所以,如果你个人开发使用,可以使用OpenJDK来代替Oracle的JDK。

在macOS平台,可以通过 Homebrew 来完成Java不同版本的安装。但是需要注意,虽然我们可以通过 brew cask install java 安装JDK,但是默认安装的是最新版本 JDK 14,所以我们需要通过以下方式使用 AdoptOpenJDK 提供了旧版本,如Java 8:

brew tap adoptopenjdk/openjdk
brew cask install adoptopenjdk8

如果出现 Error: Cask adoptopenjdk8 exists in multiple taps 报错提示,则需要使用完整路径指定安装:

brew cask install adoptopenjdk/openjdk/adoptopenjdk8

上述方法甚至可以安装不同版本JDK:

brew tap adoptopenjdk/openjdk

brew cask install adoptopenjdk8
brew cask install adoptopenjdk9
brew cask install adoptopenjdk10
brew cask install adoptopenjdk11

安装的jdk8,位于 /Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/bin/java

安装了多个版本jdk,可以通过 jenv 管理版本:

brew install jenv

然后设置 ~/.zshrc

export PATH="$HOME/.jenv/bin:$PATH"
eval "$(jenv init -)"

然后设置版本:

jenv add /Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home

此时提示:

openjdk64-1.8.0.252 added
1.8.0.252 added
1.8 added

例如,再添加jdk 14:

jenv add /Library/Java/JavaVirtualMachines/adoptopenjdk-14.jdk/Contents/Home

然后就可以通过 /usr/libexec/java_home -verbose 检查系统安装的JDK版本:

Matching Java Virtual Machines (2):
    14.0.1, x86_64:"AdoptOpenJDK 14": /Library/Java/JavaVirtualMachines/adoptopenjdk-14.jdk/Contents/Home
    1.8.0_252, x86_64:"AdoptOpenJDK 8": /Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home

可以看到现在的java位置 which java 显示是 /Users/huatai/.jenv/shims/java ,当前的 java -version 输出就是:

openjdk version "14.0.1" 2020-04-14
OpenJDK Runtime Environment AdoptOpenJDK (build 14.0.1+7)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 14.0.1+7, mixed mode, sharing)
  • 检查当前已经添加的Java版本:

    jenv versions
    

jenv使用

备注

对于开发者来说,系统中需要安装多个JDK版本进行兼容性验证。部分开发项目需要指定特定的JDK版本运行,每次手工切换实在是非常麻烦。

jenv 提供了一个非常灵活便捷的设置方式,只需要在执行目录下存放一个 .java-version 文件配置了Java版本,则进入该目录运行Java程序就会以指定的Java版本运行。

有两种jenv版本设置方式,一种是当前工作目录的本地Java版本,将在当前目录下创建一个 .java-version 文件,这个文件可以添加到项目的git仓库中。 jenv 可以在当前目录下启动shell时正确加载java版本:

jenv local 1.8
exec $SHELL -l
cat .java-version

此时显示 .java-version 内容是 1.8 ,我们现在来验证一下:

java -version

则显示输出:

openjdk version "1.8.0_252"
OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_252-b09)
OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.252-b09, mixed mode)

而没有设置 jenv local 的全局版本显示 java -version 输出为:

openjdk version "14.0.1" 2020-04-14
OpenJDK Runtime Environment AdoptOpenJDK (build 14.0.1+7)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 14.0.1+7, mixed mode, sharing)

上述设置只要是环境shell中初始化了jenv,则只要进入设置了 .java-version 的程序目录,则 java -version 自动会切换到指定Java版本,非常方便。

对于全局性Java版本,则使用:

jenv global 14

这样通常情况下就会使用JDK 14来运行程序。

通过Docker运行JDK8

此外可以通过 Docker Atlas 获取官方提供的旧版本JDK容器,好处是不需要手工安装JDK并保持了主机的简洁,而且可以通过切换容器来切换Java版本。

  • 创建 Dockerfile

    FROM java:8
    COPY . /usr/src/myapp
    WORKDIR /usr/src/myapp
    
  • 创建 docker-compose.yml 文件:

    version: "2"
    
    services:
      java:
        build: .
        volumes:
          - .:/usr/src/myapp
    
  • 然后我们编辑一个java程序文件:

    public class HelloWorld {
        public static void main(String[] args) {
            System.out.println("Hello, World");
        }
    }
    
  • 编译java:

    docker-compose run --rm java javac HelloWorld.java
    
  • 然后我们就可以运行了:

    docker-compose run --rm java java HelloWorld
    

参考