簡體   English   中英

如何在線程java應用程序中確定運行時的主類?

[英]How to determine main class at runtime in threaded java application?

我想在運行時確定我的應用程序啟動的類名,帶有main()方法的類名,但我在另一個線程中,我的堆棧跟蹤不會一直回到原始類。

我搜索了系統屬性以及ClassLoader提供的所有內容,並且沒有提供任何內容。 這些信息不可用嗎?

謝謝。

請參閱Tom Hawtin給出的評論鏈接。 這些天的解決方案是(僅限Oracle JVM):

public static String getMainClassAndArgs() {
    return System.getProperty("sun.java.command"); // like "org.x.y.Main arg1 arg2"
}

僅使用Oracle Java 7進行測試。有關特殊情況的更多信息: http//bugs.java.com/view_bug.do?video_id = 4827318

根據平台,JAVA_MAIN_CLASS環境值並不總是存在。 如果您只想獲得啟動Java進程的“main”類的名稱,則可以執行以下操作:

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

嘗試使用Thread.getAllStackTraces() 它從所有正在運行的線程返回堆棧跟蹤的Map,而不僅僅是當前線程。

我想到了。 任何人都可以告訴我這個環境變量是否總是在操作系統的其他Java實現中出現? 這在Oracle JVM上產生類似“org.xyClassName”的字符串

public static String getMainClassName() {
  for (final Map.Entry<String, String> entry : System.getenv().entrySet())
    if (entry.getKey().startsWith("JAVA_MAIN_CLASS")) // like JAVA_MAIN_CLASS_13328
      return entry.getValue();
  throw new IllegalStateException("Cannot determine main class.");
}

鑒於澄清,我建議使用“從上面參數化”的習語。 你有信息開始,保持它。

我做了一個RFE 4827318 (六年前!)用於測試跑步者這樣的事情。

即使具有main()方法的線程已終止且您未使用Oracle JVM,您仍可以嘗試從操作系統獲取信息。 下面的代碼獲取了用於在Linux下啟動JVM的命令行,但您可以為Windows編寫一個版本等。然后,您可以查看JVM的參數以查找應用程序入口點。 它可能直接在命令行上,或者您可能在指定jar的清單中查找Main-Class:classname。 我首先使用System.getProperty(“sun.java.command”),朋友只有在必要時才會回到這個機制。

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");
}

獲取主類的另一種方法是在Thread.getAllStackTraces上查找該類,因此您甚至可以在jar中找到它,它適用於任何SDK(Open,Oracle ...):

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;
    }
}

怎么樣的:

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);
        }
    }
}

這會給你類似的東西

java.lang.Object.wait(Native Method)
java.lang.Object.wait(Object.java:231)
java.lang.Thread.join(Thread.java:680)
com.mypackage.Runner.main(Runner.java:10)

雖然主線程可能不被稱為"main"但可能更好地檢查包含的堆棧跟蹤元素(main

編輯如果主線程退出,這是不行的!

我建議將此信息放入系統屬性中。 從腳本啟動應用程序時,這通常很簡單。

如果你不能這樣做,我建議在每個應用程序的main()方法中設置屬性。 這里最簡單的方法是讓每個應用程序從一個公共基類派生它的“主類”並在那里運行一個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) {
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM