我想在運行時確定應用程序啓動的類名(使用main()方法的類),但是我在另一個線程中,並且我的堆棧跟蹤沒有回到原始類。如何確定線程java應用程序運行時的主類?
我已經搜索了系統屬性和ClassLoader所提供的一切,並且什麼也沒有提供。這些信息是否不可用?
謝謝。
我想在運行時確定應用程序啓動的類名(使用main()方法的類),但是我在另一個線程中,並且我的堆棧跟蹤沒有回到原始類。如何確定線程java應用程序運行時的主類?
我已經搜索了系統屬性和ClassLoader所提供的一切,並且什麼也沒有提供。這些信息是否不可用?
謝謝。
我想通了。任何人都可以告訴我這個環境變量是否會一直存在於跨操作系統的其他Java實現中?這在Oracle JVM產生像「org.x.y.ClassName」
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.");
}
嘗試使用Thread.getAllStackTraces()。它從所有正在運行的線程中返回一個堆棧跟蹤的Map,而不僅僅是當前的線程。
如何像:
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
編輯如果主thr ead退出了,這不好!
鑑於澄清,我建議用成語「從上面參數化」的字符串。你有信息開始,保持它。
我確實在一個RFE 4827318(六年前!)爲此類測試跑步者使用。
我建議把這些信息放到一個系統屬性中。從腳本啓動應用程序時,這通常很簡單。
如果你不能這樣做,我建議在每個應用程序的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) {
}
}
請參閱Tom Hawtin給出的鏈接評論。一個解決辦法是這些天(甲骨文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?bug_id=4827318
的JAVA_MAIN_CLASS環境價值並不總是存在取決於平臺。如果你只是想獲得的是開始您的Java進程的「主」類的名字,你可以這樣做:
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」)和朋友,如果有必要的話只能回到這個機制。
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該類,所以你能找到它甚至罐子裏面,它適用於任何SDK(開放,甲骨文...):
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;
}
}
我很好奇,如果你能解釋一下爲什麼你正在尋找這個..? – 2009-06-02 14:41:40
用於在多個應用程序的通用配置文件中設置日誌級別。 – 2009-06-02 14:55:51
我同意馬特b。在我看來,這絕不是必要的。聽起來好像你的系統比自己更擅長自我感知。 – 2009-06-02 14:56:48