Мне нужен чистый способ запуска многих экземпляров программы Java с графическим интерфейсом, и я хочу сделать это программно. «Программа», которую я хочу запустить, представляет собой просто файл .class (скомпилированный файл .java с основным методом), он должен отображать графический интерфейс и работать независимо от других (как собственный процесс). Мне также нужно передать этой программе некоторые аргументы.
Проверьте EDIT5 для получения полного кода рабочего решения.
Вот класс, который должен запускать множество процессов
package startothermain;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Starter {
public static void main(String[] args) {
int starts = 4;
for (int i = 0; i < starts; ++i) {
System.out.println("Starting an app");
ProcessBuilder pb = new ProcessBuilder("java.exe", "-cp", "bin", "Started", "arg0");
try {
pb.start();
} catch (IOException ex) {
Logger.getLogger(Starter.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
Это класс, который должен запускаться и отображать графический интерфейс.
package startothermain;
import javax.swing.JOptionPane;
public class Started {
public static void main(String[] args) {
JOptionPane.showMessageDialog(null, args[0]);
}
}
Я пробовал предложения ProcessBuilder и Runtime.getRuntime(), которые я нашел в других ответах, но они, похоже, не работают. Я всегда получаю какую-то ошибку «не найдено», например эту
SEVERE: null
java.io.IOException: Cannot run program "java.exe": error=2, No such file or directory
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1041)
at startothermain.Starter.main(Starter.java:35)
Caused by: java.io.IOException: error=2, No such file or directory
at java.lang.UNIXProcess.forkAndExec(Native Method)
at java.lang.UNIXProcess.<init>(UNIXProcess.java:135)
Я работаю в NetBeans и нажимаю кнопку «Выполнить», поэтому файлы .java должны быть правильно скомпилированы и находиться в одной папке. Я надеюсь, что это не побочная проблема с папками src/build, созданными IDE.
РЕДАКТИРОВАТЬ: я пытался найти java.exe, но я на Linux. Вздох. Я изменил его на «java», но у меня все та же проблема. Должна быть установлена переменная пути. Более того, я беспокоюсь, что если я укажу ему полный путь, он станет непереносимым.
Попытка получить JAVA_HOME в Linux
System.getenv("JAVA_HOME"); // returns null
System.getProperty("java.home"); // returns /usr/lib/jvm/java-7-openjdk-amd64/jre
И в Windows
System.getenv("JAVA_HOME"); // returns C:\Program Files\Java\jdk1.7.0_51
System.getProperty("java.home"); // returns C:\Program Files\Java\jdk1.7.0_51\jre
EDIT2: этот новый код НЕ порождает ошибок, но и не открывает графический интерфейс. Я пробовал это как в Windows, так и в Linux, с теми же результатами.
String javaHome = System.getProperty("java.home");
ProcessBuilder pb = new ProcessBuilder(javaHome + "/bin/java", "-cp", "bin", "Started", "arg0");
EDIT3: я перенаправил потоки ошибок и вывода построителя процессов (а не созданных процессов), и оказалось, что Java ClassLoader не может найти класс. Я предполагаю, что проблема не в JAVA_HOME, а в проблеме пути.
Вот новый код
package startothermain;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Starter {
public static void main(String[] args) {
int starts = 4;
System.out.println(System.getProperty("java.home")); // prints C:\Program Files\Java\jdk1.7.0_51\jre
System.out.println(System.getenv("JAVA_HOME")); // prints C:\Program Files\Java\jdk1.7.0_51
System.out.println("Working Directory = "
+ System.getProperty("user.dir")); // prints C:\Users\Agostino\Documents\NetBeansProjects\StartOtherMain
for (int i = 0; i < starts; ++i) {
System.out.println("Starting an app");
ProcessBuilder pb = new ProcessBuilder("java", "build.classes.startothermain.Started");
File log = new File("log");
pb.redirectOutput(log);
pb.redirectError(log);
try {
pb.start();
} catch (IOException ex) {
Logger.getLogger(Starter.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
В лог-файле я нахожу эту ошибку
java.lang.NoClassDefFoundError: build/classes/startothermain/Started (wrong name: startothermain/Started)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:482)
Exception in thread "main"
EDIT4: теперь код работает, но если я попытаюсь использовать библиотеку .jar в классе Started, ее невозможно будет найти.
См. этот класс Started, который использует библиотеку .jar (JavaTuples), которая добавляется в библиотеки проекта через NetBeans.
package startothermain;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Starter {
public static void main(String[] args) {
int starts = 1;
for (int i = 0; i < starts; ++i) {
System.out.println("Starting an app");
ProcessBuilder pb = new ProcessBuilder();
String fullClassName = Started.class.getName();
pb.command("java", "-cp", "./build/classes", fullClassName, "myArg");
File log = new File("log");
pb.redirectOutput(log);
pb.redirectError(log);
try {
pb.start();
} catch (IOException ex) {
Logger.getLogger(Starter.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
Фиксированный начальный класс
package startothermain;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Starter {
public static void main(String[] args) {
int starts = 1;
for (int i = 0; i < starts; ++i) {
System.out.println("Starting an app");
ProcessBuilder pb = new ProcessBuilder();
String fullClassName = Started.class.getName();
pb.command("java", "-cp", "./build/classes", fullClassName, "myArg");
File log = new File("log");
pb.redirectOutput(log);
pb.redirectError(log);
try {
pb.start();
} catch (IOException ex) {
Logger.getLogger(Starter.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
Ошибка в журнале ProcessBuilder
Exception in thread "main" java.lang.NoClassDefFoundError: org/javatuples/Pair
at startothermain.Started.main(Started.java:28)
Caused by: java.lang.ClassNotFoundException: org.javatuples.Pair
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
... 1 more
EDIT5: Рабочий код
Стартовый класс
package startothermain;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Starter {
public static void main(String[] args) {
int starts = 1;
for (int i = 0; i < starts; ++i) {
System.out.println("Starting an app");
ProcessBuilder pb = new ProcessBuilder();
String fullClassName = Started.class.getName();
String pathToClassFiles = new File("./build/classes").getPath();
String pathSeparator = File.pathSeparator; // ":" on Linux, ";" on Windows
String pathToLib = new File("./lib/javatuples-1.2.jar").getPath();
pb.command("java", "-cp", pathToLib + pathSeparator + pathToClassFiles, fullClassName, "myArg");
File log = new File("log" + i + ".txt"); //debug log for started process
try {
pb.redirectOutput(log);
pb.redirectError(log);
pb.start();
} catch (IOException ex) {
Logger.getLogger(Starter.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
Начал занятие
package startothermain;
import javax.swing.JOptionPane;
import org.javatuples.Pair;
public class Started {
public static void main(String[] args) {
Pair<String, Integer> pair = Pair.with("One", 1);
JOptionPane.showMessageDialog(null, args[0] + " " + pair);
}
}
"/bin/bash", "-c", "/usr/bin/java -cp ..."
, если/usr/bin/java", "-cp", ...
у вас не работает. Вызов праймера выполнит команду java в вашем терминале. - person Roman Vottner   schedule 17.01.2014JAVA_HOME
переменную среды, а затем вызвать исполняемый файл Java в каталоге/bin
. В зависимости от ОС, в которой вы работаете - person Roman Vottner   schedule 17.01.2014/usr/bin/java
, как вы указали в комментарии ранее. Поэтому либо просто используйте"/usr/bin/java", "-cp",...
, либо, как указано в комментарии, перед вызовом команды, отправив команду в вашу оболочку"/bin/bash", "-c", "/usr/bin/java -cp ..."
. И вы должны установить (экспортировать) свой JAVA_HOME! - person Roman Vottner   schedule 18.01.2014"/usr/bin/java", "-cp",...
работает только наполовину (выполняется без ошибок, но не открывает ни один из графических интерфейсов). РЕДАКТИРОВАТЬ: java -version работает в Bash, вы уверены, что он не установлен? - person Agostino   schedule 18.01.2014build.classes.startothermain.Started
полным именем класса? (так что пакетbuild.classes.startothermain
?) Если пакет толькоstartothermain
и классStarted
, это может быть ошибкой. Дополнительная информация доступна здесь. Я думаю, что команда должна быть скорее"java", "-cp", "./build/classes", "startothermain.Started"
- person Roman Vottner   schedule 19.01.2014