4

macOS 如何定位 JAVA_HOME

 1 year ago
source link: https://yanbin.blog/macos-how-to-locatate-java_home/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

macOS 如何定位 JAVA_HOME

2022-03-18 — Yanbin

多数的 Java 入门教程都是要求同时设置 JAVA_HOME 和 PATH(包含 $JAVA_HOME/bin) 两个环境变量,反正两个都有了就保险。其实一般情况下系统能在 PATH 中找到 java 程序时就知道 JAVA_HOME, 基本上只要配置 PATH 就行,而 JAVA_HOME 环境变量是可选的。但也有例外,比如 TOMCAT 就可能要求有 JAVA_HOME 环境变量。

在 macOS 下,JAVA_HOME 与 PATH 的关系又显得有点微妙了。一个新的 macOS 系统,它自带有 java 命令

$ which java
/usr/bin/java

你要直接执行它的话

$ java
The operation couldn’t be completed. Unable to locate a Java Runtime.
Please visit http://www.java.com for information on installing Java.

所以它实际上只是执行 java 的辅助入口,没有实际的 JDK 或 JRE 是没用的。

用 PATH 覆盖 /usr/bin/java

当我们把 JDK 安装在非默认目录,如 /Users/yanbin/amazon-corretto-11.jdk,我们可以配置 PATH 来使用这个 JDK

export PATH=/Users/yanbin/amazon-correto-11.jdk/Contents/Home/bin:$PATH

然后可以执行

$ java -version
openjdk version "11.0.14.1" 2022-02-08 LTS

注意自己的路径要放在 $PATH 之前,否则仍然会执行 /usr/bin/java, 从而找不到 Java

macOS 定位 JAVA_HOME 有一个自己的命令 /usr/libexec/java_home, /usr/bin/java 就是仰赖于它来定位 JAVA_HOME 的。如果  JDK 在非默认目录中,/usr/libexec/java_home 是不知道的

$ /usr/libexec/java_home
The operation couldn’t be completed. Unable to locate a Java Runtime.
Please visit http://www.java.com for information on installing Java.

虽然依据 PATH 是可以执行 java 程序的。

/usr/libexec/java_home 定位

前面提到 macOS 的 JDK 安装默认目录,那就是 /Library/Java/JavaVirtualMachines, JDK 安装程序会安装 JDK 到该目录中,如

/Library/Java/JavaVirtualMachines/amazon-corretto-11.jdk

这时候我们不需要配置 PATH 环境变量(把 PATH 环境变量恢复成默认,或打开一个新的终端),再执行 /usr/libexec/java_home 就能找到该默认位置下的 JDK11

$ /usr/libexec/java_home
/Library/Java/JavaVirtualMachines/amazon-corretto-11.jdk/Contents/Home

执行 java

$ java -version
openjdk version "11.0.14.1" 2022-02-08 LTS

不光是执行 JDK 安装程序的方式,就是我们直接解压 JDK 到目录也行。例如我们解压 JDK 8 到该目录中

$ ls /Library/Java/JavaVirtualMachines
amazon-corretto-11.jdk amazon-corretto-8.jdk

看看此时 macOS 会选择哪个 JDK

$ /usr/libexec/java_home
/Library/Java/JavaVirtualMachines/amazon-corretto-11.jdk/Contents/Home
$ /usr/libexec/java_home -V
Matching Java Virtual Machines (2):
11.0.14.1 (x86_64) "Amazon.com Inc." - "Amazon Corretto 11" /Library/Java/JavaVirtualMachines/amazon-corretto-11.jdk/Contents/Home
1.8.0_322 (x86_64) "Amazon" - "Amazon Corretto 8" /Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home
/Library/Java/JavaVirtualMachines/amazon-corretto-11.jdk/Contents/Home
$java -version
openjdk version "11.0.14.1" 2022-02-08 LTS

列出来两个 JDK, 但选择了 JDK 11

再来一个 JDk

$ ls /Library/Java/JavaVirtualMachines
amazon-corretto-11.jdk amazon-corretto-17.jdk amazon-corretto-8.jdk

$ /usr/libexec/java_home -V
Matching Java Virtual Machines (3):
    17.0.2 (x86_64) "Amazon.com Inc." - "Amazon Corretto 17" /Library/Java/JavaVirtualMachines/amazon-corretto-17.jdk/Contents/Home
    11.0.14.1 (x86_64) "Amazon.com Inc." - "Amazon Corretto 11" /Library/Java/JavaVirtualMachines/amazon-corretto-11.jdk/Contents/Home
    1.8.0_322 (x86_64) "Amazon" - "Amazon Corretto 8" /Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home
/Library/Java/JavaVirtualMachines/amazon-corretto-17.jdk/Contents/Home
$ java -version
openjdk version "17.0.2" 2022-01-18 LTS

看来在 /Library/Java/JavaVirtualMachines 中有多个 JDK 版本时,/usr/libexec/java_home 会选择最高版本。

用 JAVA_HOME 选择 JDK 版本

那么如何让 /usr/bin/java 选择自己想要的 JDK 版本呢,设定 JAVA_HOME, 而不是让 /usr/libexec/java_home 自主选择最高的版本。

比如我们在 /Library/Java/JavaVirtualMachines 中有三个 JDK 版本时,想用 JDK 8

export JAVA_HOME=/Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home
$ java -version
openjdk version "1.8.0_322"

/usr/libexec/java_home 的高级用法

$ /usr/libexec/java_home --help
Usage: java_home [options...]
    Returns the path to a Java home directory from the current user's settings.
Options:
    [-v/--version   <version>]       Filter versions (as if JAVA_VERSION had been set in the environment).
    [-a/--arch      <architecture>]  Filter architecture (as if JAVA_ARCH had been set in the environment).
    [-F/--failfast]                  Fail when filters return no JVMs, do not continue with default.
    [   --exec      <command> ...]   Execute the $JAVA_HOME/bin/<command> with the remaining arguments.
    [-X/--xml]                       Print full JVM list and additional data as XML plist.
    [-V/--verbose]                   Print full JVM list with architectures.
    [-h/--help]                      This usage information.

除了 /usr/libexec/java_home -V 可列出 /Library/Java/JavaVirtualMachines 中的所有 JDK 版本及路径,以及首选的 JDK 外,用 /usr/libexec/java_home -X 能以 plist XML 格式展示所有 JDK

$ /usr/libexec/java_home -X

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
    <dict>
        <key>JVMArch</key>
        <string>x86_64</string>
        <key>JVMBundleID</key>
        <string>com.amazon.corretto.18</string>
        <key>JVMEnabled</key>
        <true/>
        <key>JVMHomePath</key>
        <string>/Library/Java/JavaVirtualMachines/amazon-corretto-18.jdk/Contents/Home</string>
        <key>JVMName</key>
        <string>Amazon Corretto 18</string>
        <key>JVMPlatformVersion</key>
        <string>18.0.0</string>
        <key>JVMVendor</key>
        <string>Amazon.com Inc.</string>
        <key>JVMVersion</key>
        <string>18.0.0</string>
    </dict>
    <dict>
        <key>JVMArch</key>
        <string>x86_64</string>
        <key>JVMBundleID</key>
        <string>com.amazon.corretto.17</string>
        <key>JVMEnabled</key>
        <true/>
        <key>JVMHomePath</key>
        <string>/Library/Java/JavaVirtualMachines/amazon-corretto-17.jdk/Contents/Home</string>
        <key>JVMName</key>
        <string>Amazon Corretto 17</string>
        <key>JVMPlatformVersion</key>
        <string>17.0.2</string>
        <key>JVMVendor</key>
        <string>Amazon.com Inc.</string>
        <key>JVMVersion</key>
        <string>17.0.2</string>
    </dict>
    <dict>
        <key>JVMArch</key>
        <string>x86_64</string>
        <key>JVMBundleID</key>
        <string>com.amazon.corretto.11</string>
        <key>JVMEnabled</key>
        <true/>
        <key>JVMHomePath</key>
        <string>/Library/Java/JavaVirtualMachines/amazon-corretto-11.jdk/Contents/Home</string>
        <key>JVMName</key>
        <string>Amazon Corretto 11</string>
        <key>JVMPlatformVersion</key>
        <string>11.0.14</string>
        <key>JVMVendor</key>
        <string>Amazon.com Inc.</string>
        <key>JVMVersion</key>
        <string>11.0.14.1</string>
    </dict>
    <dict>
        <key>JVMArch</key>
        <string>x86_64</string>
        <key>JVMBundleID</key>
        <string>com.amazon.corretto.8</string>
        <key>JVMEnabled</key>
        <true/>
        <key>JVMHomePath</key>
        <string>/Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home</string>
        <key>JVMName</key>
        <string>Amazon Corretto 8</string>
        <key>JVMPlatformVersion</key>
        <string>1.8</string>
        <key>JVMVendor</key>
        <string>Amazon</string>
        <key>JVMVersion</key>
        <string>1.8.0_322</string>
    </dict>
</array>
</plist>

还能用 /usr/libexec/java_home -v xxx 智能的显示所对应版本的 JAVA_HOME

$ /usr/libexec/java_home -v 1.8
/Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home
$ /usr/libexec/java_home -v 11
/Library/Java/JavaVirtualMachines/amazon-corretto-11.jdk/Contents/Home
$ /usr/libexec/java_home -v 8
/Library/Java/JavaVirtualMachines/amazon-corretto-18.jdk/Contents/Home

结合 /usr/libexec/java_home -v xxx 选项,我们就可以用一个脚本来切换 JAVA_HOME,核心就是

export JAVA_HOME=$(/usr/libexec/java_home -v $1)

根据所使用 shell 的不同,比如我们可以在 ~/.bashrc 或 ~/.zshrc 文件中定义一个函数

switch_java() {
  JAVA_HOME=$(/usr/libexec/java_home -v $1)
  if [ -z $2 ]; then
    echo "switch JAVA_HOME to $JAVA_HOME"
  export JAVA_HOME
# set default JAVA_HOME
switch_java 11 XX

然后执行 switch_java 来切换

$ switch_java 11
$ switch_java 1.8
$ switch_java 17

$  java -version
openjdk version "11.0.14.1" 2022-02-08 LTS
OpenJDK Runtime Environment Corretto-11.0.14.10.1 (build 11.0.14.1+10-LTS)
OpenJDK 64-Bit Server VM Corretto-11.0.14.10.1 (build 11.0.14.1+10-LTS, mixed mode)
$  switch_java 1.8
switch JAVA_HOME to /Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home
$  java -version
openjdk version "1.8.0_322"
OpenJDK Runtime Environment Corretto-8.322.06.1 (build 1.8.0_322-b06)
OpenJDK 64-Bit Server VM Corretto-8.322.06.1 (build 25.322-b06, mixed mode)

如果把 export JAVA_HOME=$(/usr/libexec/java_home -v $1) 定义在别的脚本文件中要用 source switch_java.sh 1.8 来切换

最后注意在用 /usr/libexec/java_home 定位 JAVA_HOME 时不需要为 JAVA 定制 PATH,要以 /usr/bin/java 作为入口。

javac 也一样

$ which javac
/usr/bin/javac

更多 /usr/bin 下的 java 命令

$ ls /usr/bin/j*
/usr/bin/jar          /usr/bin/javah        /usr/bin/jconsole     /usr/bin/jhsdb        /usr/bin/jmap         /usr/bin/jpackage     /usr/bin/json_pp      /usr/bin/jstack
/usr/bin/jarsigner    /usr/bin/javap        /usr/bin/jcontrol     /usr/bin/jimage       /usr/bin/jmc          /usr/bin/jps          /usr/bin/json_pp5.18  /usr/bin/jstat
/usr/bin/java         /usr/bin/javapackager /usr/bin/jdb          /usr/bin/jinfo        /usr/bin/jobs         /usr/bin/jrunscript   /usr/bin/json_pp5.30  /usr/bin/jstatd
/usr/bin/javac        /usr/bin/javaws       /usr/bin/jdeps        /usr/bin/jjs          /usr/bin/join         /usr/bin/jsadebugd    /usr/bin/json_xs      /usr/bin/jvisualvm
/usr/bin/javadoc      /usr/bin/jcmd         /usr/bin/jhat         /usr/bin/jlink        /usr/bin/jot          /usr/bin/jshell       /usr/bin/json_xs5.30

如果有 JDK 中无法被 /usr/bin 下 j* 覆盖的命令,就要从 $JAVA_HOME/bin 中找,所以必要时在修改 JAVA_HOME 环境变量后,也应更新 PATH 环境变量。

关于 Linux 下如何找到 JAVA_HOME, 有两个命令

sh-4.2# dirname $(dirname $(readlink -f $(which javac)))
/usr/lib/jvm/java-11-openjdk-11.0.14.1.1-1.el7_9.x86_64
sh-4.2# java -XshowSettings:properties -version 2>&1 > /dev/null | grep 'java.home'
    java.home = /usr/lib/jvm/java-11-openjdk-11.0.14.1.1-1.el7_9.x86_64
  1. How to Find JAVA_HOME

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK