55 Stimmen

Ausführen einer Java-Anwendung in einem separaten Prozess

Kann eine Java-Anwendung plattformunabhängig in einem separaten Prozess unter Verwendung ihres Namens und nicht ihres Speicherorts geladen werden?

Ich weiß, dass man ein Programm über ... ausführen kann.

Process process = Runtime.getRuntime().exec( COMMAND );

... das Hauptproblem dieser Methode ist, dass solche Aufrufe dann plattformspezifisch sind.

Im Idealfall würde ich eine Methode in etwas so Einfaches wie... verpacken.

EXECUTE.application( CLASS_TO_BE_EXECUTED );

... und geben Sie den voll qualifizierten Namen einer Anwendungsklasse als CLASS_TO_BE_EXECUTED .

1 Stimmen

Also, wenn ich Sie richtig verstehe, haben Sie mehrere Klassen mit main()-Methoden und Sie wollen sie in separaten Prozessen zu starten?

0 Stimmen

Wie wäre es, wenn Sie exec("java.exe", CLASS_TO_BE_EXECUTED.class.getName()) ?

0 Stimmen

Wie man Eingaben von einem Benutzer für eine Java-Klasse, die als Prozess läuft, der selbst von einem Java-Programm gestartet wird, mit etwas wie br.readLine() entgegennimmt

85voto

hallidave Punkte 8669

Dies ist eine Zusammenfassung einiger der anderen Antworten, die gegeben wurden. Die Java-Systemeigenschaften bieten genügend Informationen, um den Pfad zum Java-Befehl und den Klassenpfad auf eine, wie ich glaube, plattformunabhängige Weise zu ermitteln.

public final class JavaProcess {

    private JavaProcess() {}        

    public static int exec(Class klass, List<String> args) 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.getName();

        List<String> command = new LinkedList<String>();
        command.add(javaBin);
        command.add("-cp");
        command.add(classpath);
        command.add(className);
        if (args != null) {
            command.addAll(args);
        }

        ProcessBuilder builder = new ProcessBuilder(command);

        Process process = builder.inheritIO().start();
        process.waitFor();
        return process.exitValue();
    }

}

Sie würden diese Methode wie folgt ausführen:

int status = JavaProcess.exec(MyClass.class, args);

Ich dachte, es machte Sinn, in der tatsächlichen Klasse statt der String-Darstellung des Namens übergeben, da die Klasse in den Klassenpfad sowieso für diese zu arbeiten hat.

5 Stimmen

Sie müssen möglicherweise Folgendes verwenden redirectOutput(...) y redirectError(...) auf dem Process Builder (vor start() ), wenn Sie eine Art von Server starten wollen, sonst könnte er hängen bleiben und Sie könnten nicht in der Lage sein, ihn zu kontaktieren. Ich weiß allerdings nicht, warum...

0 Stimmen

Wie kann der neue Prozess im abgetrennten Modus ausgeführt werden, so dass der äußere Prozess seine Arbeit fortsetzen kann?

0 Stimmen

Danke! Die Trennung von "-cp" und dem eigentlichen Klassenpfad hat geholfen. Wenn man sie zusammen als einen einzigen String macht, kommt die Fehlermeldung "Unrecognized option: -cp <blah>".

47voto

stepancheg Punkte 4124

Zwei Hinweise:

System.getProperty("java.home") + "/bin/java" gibt Ihnen einen Pfad zur ausführbaren Java-Datei.

((URLClassLoader) Thread.currentThread().getContextClassLoader()).getURL() hilft Ihnen, den Klassenpfad der aktuellen Anwendung zu rekonstruieren.

Dann wird Ihr EXECUTE.application ist einfach (Pseudocode):

Process.exec(javaExecutable, "-classpath", urls.join(":"), CLASS_TO_BE_EXECUTED)

12 Stimmen

Dritter Hinweis: Verwenden Sie urls.join(":") nicht, wenn Sie plattformunabhängig sein wollen.

5 Stimmen

File.some_constant anstelle von : (Sie können some_constant nachschlagen :-)

0 Stimmen

Mit dem URL-Ansatz erhalte ich die URL zur JAR-Datei aus der Codebasis der JNLP-Datei, d. h. url.com/Jar.jar . Das funktioniert bei mir nicht. Als es noch lokal war, ging es.

5voto

StaxMan Punkte 107669

Das mag für Sie ein Overkill sein, aber Projekt Akuma tut, was Sie wollen und mehr. Ich habe es gefunden über diese Eingabe in Kohsukes (einem von Suns Startprogrammierern) fabelhaft nützlichem Blog.

1 Stimmen

Sieht so aus, als wäre es nach Github verschoben worden. Macht Sinn, wenn man bedenkt, wie sauer Oracle mit der ganzen Jenkins/Hudson-Sache wurde.

5voto

andrej Punkte 186

In Erweiterung der Antwort von @stepancheg würde der eigentliche Code so aussehen (in Form eines Tests).

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.getName()
                // main class arguments go here
        )
                .inheritIO()
                .start();
        int exitCode = process.waitFor();
        System.out.println("process stopped with exitCode " + exitCode);
    }
}

4voto

Ande Turner Punkte 6828
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;
    }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X