Выполнение приложения Java в отдельном процессе
Может ли приложение Java загружаться в отдельный процесс, используя его имя, в отличие от его местоположения, независимо от платформы?
Я знаю, что вы можете выполнить программу через …
Process process = Runtime.getRuntime().exec( COMMAND );
… Основная проблема этого метода заключается в том, что такие вызовы являются специфическими для платформы.
- как скомпилировать и запустить java-программу в другой Java-программе?
- Linux: Есть ли что-то похожее на «верх» для ввода-вывода?
- Открыть файл с соответствующим приложением
- Как получить STDOUT из QProcess?
- Как определить, что начинается с процесса?
В идеале, я бы обернул метод во что-то простое …
EXECUTE.application( CLASS_TO_BE_EXECUTED );
… и передать полное имя classа приложения как CLASS_TO_BE_EXECUTED
.
- Почему использование ЦП в Linux превышает 100%?
- Как я могу убить процессы диспетчера задач с помощью кода VBA?
- Почему этот процесс рушится, как только он запускается?
- Инструмент / метод Java для принудительного уничтожения дочернего процесса
- .NET - WindowStyle = hidden vs. CreateNoWindow = true?
- Система (ACPI.sys) всегда использует около 15-20% моего процессора
- Доступ запрещен при получении пути процесса
- Как определить завершенный процесс Windows, если у меня все еще есть его PID?
Два намека:
System.getProperty("java.home") + "/bin/java"
дает вам путь к исполняемому файлу java.
((URLClassLoader() Thread.currentThread().getContextClassLoader()).getURL()
помогает вам восстановить ((URLClassLoader() Thread.currentThread().getContextClassLoader()).getURL()
текущего приложения.
Тогда ваш EXECUTE.application
будет просто (псевдокод):
Process.exec(javaExecutable, "-classpath", urls.join(":"), CLASS_TO_BE_EXECUTED)
Это синтез некоторых других ответов, которые были предоставлены. Свойства системы Java предоставляют достаточную информацию, чтобы найти путь к команде java и classpath в том, что, я думаю, является независимым от платформы способом.
public final class JavaProcess { private JavaProcess() {} public static int exec(Class klass) throws IOException, InterruptedException { String javaHome = System.getProperty("java.home"); String javaBin = javaHome + File.separator + "bin" + File.separator + "java"; String classpath = System.getProperty("java.class.path"); String className = klass.getCanonicalName(); ProcessBuilder builder = new ProcessBuilder( javaBin, "-cp", classpath, className); Process process = builder.start(); process.waitFor(); return process.exitValue(); } }
Вы бы запускали этот метод следующим образом:
int status = JavaProcess.exec(MyClass.class);
Я подумал, что имеет смысл передавать в фактическом classе, а не в строковое представление имени, так как class должен быть в пути к classам, чтобы это работало.
Развернувшись на ответе @ stepancheg, фактический код будет выглядеть так (в форме теста).
import org.junit.Test; import java.io.File; import java.net.URL; import java.net.URLClassLoader; import java.util.Arrays; import java.util.stream.Collectors; public class SpinningUpAJvmTest { @Test public void shouldRunAJvm() throws Exception { String classpath = Arrays.stream(((URLClassLoader) Thread.currentThread().getContextClassLoader()).getURLs()) .map(URL::getFile) .collect(Collectors.joining(File.pathSeparator)); Process process = new ProcessBuilder( System.getProperty("java.home") + "/bin/java", "-classpath", classpath, MyMainClass.class.getCanonicalName() // main class arguments go here ) .inheritIO() .start(); int exitCode = process.waitFor(); System.out.println("process stopped with exitCode " + exitCode); } }
кimport org.junit.Test; import java.io.File; import java.net.URL; import java.net.URLClassLoader; import java.util.Arrays; import java.util.stream.Collectors; public class SpinningUpAJvmTest { @Test public void shouldRunAJvm() throws Exception { String classpath = Arrays.stream(((URLClassLoader) Thread.currentThread().getContextClassLoader()).getURLs()) .map(URL::getFile) .collect(Collectors.joining(File.pathSeparator)); Process process = new ProcessBuilder( System.getProperty("java.home") + "/bin/java", "-classpath", classpath, MyMainClass.class.getCanonicalName() // main class arguments go here ) .inheritIO() .start(); int exitCode = process.waitFor(); System.out.println("process stopped with exitCode " + exitCode); } }
Это может быть излишним для вас, но Project Akuma делает то, что вы хотите, и многое другое. Я нашел его через эту запись в Kohsuke’s (один из программистов Rock Rock), сказочно полезный блог.
Вы проверили API ProcessBuilder? Он доступен с 1,5
http://java.sun.com/javase/6/docs/api/java/lang/ProcessBuilder.html
Вам действительно нужно запускать их изначально? Не могли бы вы просто назвать их «основные» методы напрямую? Единственное особенное в главном состоит в том, что пусковая установка VM называет это, ничто не мешает вам самому называть себя.
public abstract class EXECUTE { private EXECUTE() { /* Procedural Abstract */ } public static Process application( final String CLASS_TO_BE_EXECUTED ) { final String EXEC_ARGUMENT = new StringBuilder(). append( java.lang.System.getProperty( "java.home" ) ). append( java.io.File.separator ). append( "bin" ). append( java.io.File.separator ). append( "java" ). append( " " ). append( new java.io.File( "." ).getAbsolutePath() ). append( java.io.File.separator ). append( CLASS_TO_BE_EXECUTED ). toString(); try { return Runtime.getRuntime().exec( EXEC_ARGUMENT ); } catch ( final Exception EXCEPTION ) { System.err.println( EXCEPTION.getStackTrace() ); } return null; } }
Следуя тому, что TofuBeer должен был сказать: вы уверены, что вам действительно нужно открутить другую JVM? В наши дни JVM действительно поддерживает параллелизм, поэтому вы можете получить много функциональности относительно дешево, просто открутив новую тему или две (которые могут или не требуют вызова в Foo # main (String [])). За дополнительной информацией обратитесь к java.util.concurrent.
Если вы решите развиваться, вы настроились на сложность, связанную с поиском необходимых ресурсов. То есть, если ваше приложение часто меняется и зависит от кучи файлов jar, вам нужно будет отслеживать их все, чтобы они могли быть переданы в argpath classов. Кроме того, такой подход требует вывода как местоположения (в настоящее время исполняемого) JVM (что может быть неточным), так и местоположения текущего пути к classам (что еще менее вероятно, будет точным, в зависимости от того, как нерестится Был вызван stream – jar, jnlp, exploded .classes dir, некоторый контейнер и т. Д.).
С другой стороны, привязка к статическим методам #main также имеет свои недостатки. статические модификаторы имеют неприятную склонность к утечке в другой код и, как правило, недовольны дизайнерами.
Проблема, возникающая, когда вы запускаете это из графического интерфейса java, выполняется в фоновом режиме. Таким образом, вы не видите командную строку.
Чтобы обойти это, вам нужно запустить java.exe через «cmd.exe» и «start». Я не знаю почему, но если вы поместите «cmd / c start» infront, он покажет командную строку при ее запуске.
Однако проблема с «стартом» заключается в том, что если в пути к приложению есть пробел (который путь к java exe обычно имеет, как и в C: \ Program Files \ Java \ jre6 \ bin \ java.exe или аналогичный), тогда начало просто терпит неудачу с «не может найти c: \ Program»
Таким образом, вы должны ставить кавычки в C: \ Program Files \ Java \ jre6 \ bin \ java.exe. Теперь начните жаловаться на параметры, которые вы передаете java.exe: «Система не может найти файл -cp.»
Выйти из пространства в «Program Files» с обратным слэшем также не работает. Поэтому идея состоит в том, чтобы не использовать пространство. Создайте временный файл с расширением bat, а затем введите команду с пробелами и запустите bat. Тем не менее, запуск летучей мыши через старт, не завершается, поэтому вы должны поместить «exit» в конец командного файла.
Это все еще кажется yucky.
Итак, ища альтернативы, я обнаружил, что использование цитаты цитаты цитаты в пространстве «Program Files» действительно работает с запуском.
В classе EXECUTE выше измените построитель строк, добавив:
append( "cmd /C start \"Some title\" " ). append( java.lang.System.getProperty( "java.home" ).replaceAll(" ", "\" \"") ). append( java.io.File.separator ). append( "bin" ). append( java.io.File.separator ). append( "java" ). append( " " ). append( new java.io.File( "." ).getAbsolutePath() ). append( java.io.File.separator ). append( CLASS_TO_BE_EXECUTED ).