在线程化java应用程序中,如何在运行时确定主类?

在线程化java应用程序中,如何在运行时确定主类?,java,runtime,stack-trace,classloader,main,Java,Runtime,Stack Trace,Classloader,Main,我想在运行时确定我的应用程序启动的类名,即使用main()方法的类名,但我在另一个线程中,我的stacktrace不会一直返回到原始类 我搜索了系统属性和ClassLoader提供的所有内容,但没有找到任何结果。难道这些信息就是不可用吗 谢谢。尝试使用。它返回所有运行线程的堆栈跟踪映射,而不仅仅是当前线程的堆栈跟踪映射。类似于: Map<Thread,StackTraceElement[]> stackTraceMap = Thread.getAllStackTraces(); fo

我想在运行时确定我的应用程序启动的类名,即使用main()方法的类名,但我在另一个线程中,我的stacktrace不会一直返回到原始类

我搜索了系统属性和ClassLoader提供的所有内容,但没有找到任何结果。难道这些信息就是不可用吗


谢谢。

尝试使用。它返回所有运行线程的堆栈跟踪映射,而不仅仅是当前线程的堆栈跟踪映射。

类似于:

Map<Thread,StackTraceElement[]> stackTraceMap = Thread.getAllStackTraces();
for (Thread t : stackTraceMap.keySet())
{
    if ("main".equals(t.getName()))
    {
        StackTraceElement[] mainStackTrace = stackTraceMap.get(t);
        for (StackTraceElement element : mainStackTrace)
        {
            System.out.println(element);
        }
    }
}
主线程可能不保证被称为
“main”
,但最好检查包含
(main


编辑如果主线程已退出,这是不好的!

我找到了它。有人能告诉我,在其他操作系统的java实现中,这个环境变量是否总是存在吗?在Oracle JVM上,这会产生一个类似“org.x.y.ClassName”的字符串

公共静态字符串getMainClassName(){
对于(最终的Map.Entry:System.getenv().entrySet())
if(entry.getKey().startsWith(“JAVA\u MAIN\u CLASS”)//类似于JAVA\u MAIN\u CLASS\u 13328
返回条目.getValue();
抛出新的IllegalStateException(“无法确定主类”);
}

经过澄清,我建议使用“上面的参数化”习惯用法。您可以从信息开始,保留它


我(六年前)确实为类似的东西加入了一个RFE,以便与测试运行程序一起使用。

我建议将此信息放入系统属性中。当您从脚本启动应用程序时,这通常很简单

如果您不能这样做,我建议在每个应用程序的main()方法中设置属性。这里最简单的方法是让每个应用程序从公共基类派生其“main class”,并在其中运行init步骤。我经常在命令行处理中这样做:

public class Demo extends Main {
    main(String[] args) {
        Main._main(new Demo (), args);
    }

    // This gets called by Main._main()
    public void run (String[] args) {
    }
}

请参阅Tom Hawtin对link的评论。现在的解决方案是(仅限Oracle JVM):


仅使用Oracle Java 7进行测试。有关特殊情况的详细信息:

根据平台的不同,Java\u MAIN\u类环境值并不总是存在。如果您只想获取启动Java进程的“MAIN”类的名称,可以执行以下操作:

  public static String getMainClassName()
  {
    StackTraceElement trace[] = Thread.currentThread().getStackTrace();
    if (trace.length > 0) {
      return trace[trace.length - 1].getClassName();
    }
    return "Unknown";
  } 

即使包含main()的线程方法已终止,并且您没有使用Oracle JVM。您仍然可以尝试从操作系统获取信息。下面的代码获取用于在Linux下启动JVM的命令行,但您可以为Windows等编写一个版本。然后,您可以查看JVM的参数以找到应用程序入口点。它可能会不要直接在命令行上,否则您可能会在指定jar的清单中查找Main Class:classname。我会首先使用System.getProperty(“sun.java.command”)和friends,只有在必要时才使用这种机制

public final static long getSelfPid() {
    // Java 9 only
    // return ProcessHandle.current().getPid();
    try {
        return Long.parseLong(new File("/proc/self").getCanonicalFile().getName());
    } catch( Exception e ) {
        return -1;
    }
}

public final static String getJVMCommandLine() {
    try {
        // Java 9 only
        // long pid = ProcessHandle.current().getPid();
        long pid = getSelfPid();
        byte[] encoded = Files.readAllBytes(Paths.get("/proc/"+pid+"/cmdline"));
        // assume ISO_8859_1, but could look in /proc/<pid>/environ for LANG or something I suppose
        String commandLine = new String( encoded, StandardCharsets.ISO_8859_1 ); 
        String modifiedCommandLine = commandLine.replace((char)0, ' ').trim();
        return modifiedCommandLine;
    } catch( Exception e ) {
        return null;
    }
}`
public final静态长getSelfPid(){
//仅限Java 9
//返回ProcessHandle.current().getPid();
试一试{
返回Long.parseLong(新文件(“/proc/self”).getCanonicalFile().getName());
}捕获(例外e){
返回-1;
}
}
公共最终静态字符串getJVMCommandLine(){
试一试{
//仅限Java 9
//长pid=ProcessHandle.current().getPid();
长pid=getSelfPid();
byte[]encoded=Files.readAllBytes(path.get(“/proc/”+pid+“/cmdline”);
//假设ISO_8859_1,但可以在/proc//environ中查找LANG或我认为的其他内容
字符串命令行=新字符串(编码,StandardCharsets.ISO_8859_1);
String modifiedCommandLine=commandLine.replace((char)0',).trim();
返回修改后的命令行;
}捕获(例外e){
返回null;
}
}`

以下是我在不控制主电源的情况下使用的方法:

public static Class<?> getMainClass() {
  // find the class that called us, and use their "target/classes"
  final Map<Thread, StackTraceElement[]> traces = Thread.getAllStackTraces();
  for (Entry<Thread, StackTraceElement[]> trace : traces.entrySet()) {
    if ("main".equals(trace.getKey().getName())) {
      // Using a thread named main is best...
      final StackTraceElement[] els = trace.getValue();
      int i = els.length - 1;
      StackTraceElement best = els[--i];
      String cls = best.getClassName();
      while (i > 0 && isSystemClass(cls)) {
        // if the main class is likely an ide,
        // then we should look higher...
        while (i-- > 0) {
          if ("main".equals(els[i].getMethodName())) {
            best = els[i];
            cls = best.getClassName();
            break;
          }
        }
      }
      if (isSystemClass(cls)) {
        i = els.length - 1;
        best = els[i];
        while (isSystemClass(cls) && i --> 0) {
          best = els[i];
          cls = best.getClassName();
        }
      }
      try {
        Class mainClass = Class.forName(best.getClassName());
        return mainClass;
      } catch (ClassNotFoundException e) {
        throw X_Util.rethrow(e);
      }
    }
  }
  return null;
}

private static boolean isSystemClass(String cls) {
  return cls.startsWith("java.") ||
      cls.startsWith("sun.") ||
      cls.startsWith("org.apache.maven.") ||
      cls.contains(".intellij.") ||
      cls.startsWith("org.junit") ||
      cls.startsWith("junit.") ||
      cls.contains(".eclipse") ||
      cls.contains("netbeans");
}
公共静态类getMainClass(){
//找到调用我们的类,并使用它们的“目标/类”
最终映射跟踪=Thread.getAllStackTraces();
for(条目跟踪:traces.entrySet()){
if(“main”.equals(trace.getKey().getName())){
//使用名为main的线程是最好的。。。
最终StackTraceElement[]els=trace.getValue();
int i=els.length-1;
StackTraceeElement best=els[--i];
字符串cls=best.getClassName();
而(i>0&&isSystemClass(cls)){
//如果主类可能是ide,
//那么我们应该往高处看。。。
而(i-->0){
如果(“main”.equals(els[i].getMethodName())){
最佳=els[i];
cls=best.getClassName();
打破
}
}
}
if(isSystemClass(cls)){
i=els.长度-1;
最佳=els[i];
而(isSystemClass(cls)和&i-->0){
最佳=els[i];
cls=best.getClassName();
}
}
试一试{
Class mainClass=Class.forName(best.getClassName());
返回主类;
}catch(classnotfounde异常){
抛出X_Util.rethrow(e);
}
}
}
返回null;
}
私有静态布尔isSystemClass(字符串cls){
返回cls.startsWith(“java”)||
cls.startsWith(“太阳”)||
cls.startsWith(“org.apache.maven.”)||
cls.contains(“.intellij.”)||
cls.startsWith(“org.junit”)||
cls.startsWith(“junit”)||
cls.contains(“.eclipse”)||
cls.包含(“netbeans”);
}

获取主类的另一种方法是在Thread.getAllStackTraces上查找该类,这样您甚至可以在JAR中找到它,它可以在任何SDK上工作(Open,Oracle…):

private静态类mainClass=null;
公共静态类getMainClass()
{
如果(mainClass==null)
{
Map threadSet=Thread.getAllStackTraces();
对于(Map.Entry:threadSet.entrySet())
{
对于(StackTraceElement堆栈:entry.getValue())
{
  public static String getMainClassName()
  {
    StackTraceElement trace[] = Thread.currentThread().getStackTrace();
    if (trace.length > 0) {
      return trace[trace.length - 1].getClassName();
    }
    return "Unknown";
  } 
public final static long getSelfPid() {
    // Java 9 only
    // return ProcessHandle.current().getPid();
    try {
        return Long.parseLong(new File("/proc/self").getCanonicalFile().getName());
    } catch( Exception e ) {
        return -1;
    }
}

public final static String getJVMCommandLine() {
    try {
        // Java 9 only
        // long pid = ProcessHandle.current().getPid();
        long pid = getSelfPid();
        byte[] encoded = Files.readAllBytes(Paths.get("/proc/"+pid+"/cmdline"));
        // assume ISO_8859_1, but could look in /proc/<pid>/environ for LANG or something I suppose
        String commandLine = new String( encoded, StandardCharsets.ISO_8859_1 ); 
        String modifiedCommandLine = commandLine.replace((char)0, ' ').trim();
        return modifiedCommandLine;
    } catch( Exception e ) {
        return null;
    }
}`
public static Class<?> getMainClass() {
  // find the class that called us, and use their "target/classes"
  final Map<Thread, StackTraceElement[]> traces = Thread.getAllStackTraces();
  for (Entry<Thread, StackTraceElement[]> trace : traces.entrySet()) {
    if ("main".equals(trace.getKey().getName())) {
      // Using a thread named main is best...
      final StackTraceElement[] els = trace.getValue();
      int i = els.length - 1;
      StackTraceElement best = els[--i];
      String cls = best.getClassName();
      while (i > 0 && isSystemClass(cls)) {
        // if the main class is likely an ide,
        // then we should look higher...
        while (i-- > 0) {
          if ("main".equals(els[i].getMethodName())) {
            best = els[i];
            cls = best.getClassName();
            break;
          }
        }
      }
      if (isSystemClass(cls)) {
        i = els.length - 1;
        best = els[i];
        while (isSystemClass(cls) && i --> 0) {
          best = els[i];
          cls = best.getClassName();
        }
      }
      try {
        Class mainClass = Class.forName(best.getClassName());
        return mainClass;
      } catch (ClassNotFoundException e) {
        throw X_Util.rethrow(e);
      }
    }
  }
  return null;
}

private static boolean isSystemClass(String cls) {
  return cls.startsWith("java.") ||
      cls.startsWith("sun.") ||
      cls.startsWith("org.apache.maven.") ||
      cls.contains(".intellij.") ||
      cls.startsWith("org.junit") ||
      cls.startsWith("junit.") ||
      cls.contains(".eclipse") ||
      cls.contains("netbeans");
}
private static Class<?> mainClass = null;

public static Class<?> getMainClass()
{
    if (mainClass == null)
    {
        Map<Thread, StackTraceElement[]> threadSet = Thread.getAllStackTraces();
        for (Map.Entry<Thread, StackTraceElement[]> entry : threadSet.entrySet())
        {
            for (StackTraceElement stack : entry.getValue())
            {
                try
                {
                    String stackClass = stack.getClassName();
                    if (stackClass != null && stackClass.indexOf("$") > 0)
                    {
                        stackClass = stackClass.substring(0, stackClass.lastIndexOf("$"));
                    }
                    Class<?> instance = Class.forName(stackClass);
                    Method method = instance.getDeclaredMethod("main", new Class[]
                    {
                        String[].class
                    });
                    if (Modifier.isStatic(method.getModifiers()))
                    {
                        mainClass = instance;
                        break;
                    }
                }
                catch (Exception ex)
                {
                }
            }
        }
        return mainClass;
    }
}