如何获取当前正在运行的Java命令行路径?(在符号链接之前)

5

我写了一个输出使用提示的程序。它目前会将最初在命令行输入的主jar文件路径回显。

Usage: java -jar path/to/MyJar.jar <params> ...

为了完整起见,我想确保java也被回显,因为有很多种访问java的方式(不仅仅是单词java,而且比规范路径/us/opt/java-1.8.0-u123/bin/java更短)

Usage: /us/opt/java7/bin/java -jar MyJar.jar <params> ...
Usage: ./bin/java -jar MyJar.jar <params> ...
Usage: java -jar MyJar.jar <params> ...
# whatever the user typed in

我怎样才能确定使用哪个命令行调用JVM?我想要原始的命令行值,在评估符号链接之前。
我不使用System.getProperty("java.home"),因为它不尊重原始的命令行值,只是JVM的最终“规范”位置。(在命令行上使用简单的java时,像Usage: /us/opt/java-1.8.0-u123/jre/bin/java -jar ...这样的使用说明会相当冗长。)
使用纯Java代码确定java的命令行位置是否可能?(即不使用bash中的包装脚本)

我想知道为什么会被踩。是因为问题不清楚还是因为它是重复的?在提问之前,我确实进行了搜索,但我一直得到的结果都没有解决这个特定的问题。 - 700 Software
好的,我之前不知道有相关问题。现在我已经查看过了,我会编辑我的问题以澄清。 - 700 Software
这个怎么样?https://dev59.com/Q3VD5IYBdhLWcg3wQJKT#12989117 - dimo414
@dimo414,哇,这真的很有帮助。与我之前的方法相比,getProperty("sun.java.command")是获取MyJar.jar路径的更简单方式,即使它并不完全跨平台。但是,这不是获取java可执行文件的路径。如果我能得到那个答案,我就可以完成了。 :-) - 700 Software
显示剩余3条评论
2个回答

1
使用以下命令。
jps -mlvV

这应该打印有关运行Java进程的所有内容。

ps -e应该提供可执行路径。

以下是纯Java解决方案,它不会打印用于执行应用程序的实际命令,但它会生成一个具有相同效果的命令。

import java.io.File;
import java.lang.management.ManagementFactory;
import java.util.List;
import java.util.Map.Entry;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        System.out.println("Printing command");
        createCommand();
    }
    public static void createCommand() {
        try {
            String jvm = getJvmExecutable();
            String mainClassName = findMainClass();
            String processDir = System.getProperty("user.dir");


            String arguments = getArguments();
            String classpath = ManagementFactory.getRuntimeMXBean().getClassPath();


            String command = String.format("cd %s & %s %s -classpath %s %s",processDir, jvm, arguments, classpath, mainClassName);

            System.out.println(command);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    private static String getJvmExecutable() {
        String jvm = "";
        jvm = System.getProperty("java.home");
        jvm += File.separator + "bin" + File.separator + "java";
        jvm = '"' + jvm + '"';
        return jvm;
    }

    private static String getArguments() {
        List<String> argsList = ManagementFactory.getRuntimeMXBean().getInputArguments();
        String args = argsList.stream().collect(Collectors.joining(" "));

        return args;
    }

    public static String findMainClass() throws ClassNotFoundException{
        for (Entry<Thread, StackTraceElement[]> entry : Thread.getAllStackTraces().entrySet()) {
            Thread thread = entry.getKey();
            if (thread.getThreadGroup() != null && thread.getThreadGroup().getName().equals("main")) {
                for (StackTraceElement stackTraceElement : entry.getValue()) {
                    if (stackTraceElement.getMethodName().equals("main")) {

                        try {
                            Class<?> c = Class.forName(stackTraceElement.getClassName());
                            Class[] argTypes = new Class[] { String[].class };
                            //This will throw NoSuchMethodException in case of fake main methods
                            c.getDeclaredMethod("main", argTypes);
                            return stackTraceElement.getClassName();
                        } catch (NoSuchMethodException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        return null;
    }
}

注意:它可以与普通的Java项目或普通的JAR文件一起使用,但无法与特殊的类加载器(如WAR、OSGI或Spring Boot的类加载器)一起使用。
我使用了此答案中的findMainClass()方法https://dev59.com/Nl3Va4cB1Zd3GeqPCaW-#8275751

我正在寻找一个纯Java代码解决方案,这样应用程序就可以生成自己的使用脚本。对于此目的而言,exec外部进程(例如jpsps)似乎效率低下。 - 700 Software
我澄清了问题。我已经有了主类和我的jar包的路径,但我正在寻找的是Java的路径,这不是那么简洁明了。因此,如果用户键入“java”,则使用说明可以只是“java”。如果用户键入符号链接,则只需该符号链接。我不想始终显示由System.getProperty("java.home")返回的“完整路径”。 - 700 Software
我不确定自己是否理解正确了,机器上可能安装有多个版本的Java,这就是为什么我使用 java.home 来检索启动进程时使用的JVM的原因。 - 11thdimension
我实际上并不想获取JVM的“绝对”和“规范”路径。我想要用户输入的内容,这可能只是单词java,或相对路径./mydir/bin/java,符号链接的绝对路径/usr/bin/java或完整的规范路径。我不想总是反映完整的规范路径,我想反映回用户输入的内容。 - 700 Software

0

在代码中使用此系统属性

System.getProperty("java.home");

这将返回Java Runtime Environment(JRE)的安装目录

更多信息在此处


1
我已经澄清了问题。这个答案对我没有用。 - 700 Software

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接