Hur man kompilerar och kör Java-program från ett annat Java-program

By rik

Förmågan att initiera och exekvera Java-program från en annan Java-applikation är en kraftfull egenskap som öppnar upp många möjligheter för att skapa anpassningsbara och dynamiska system. Denna kapacitet möjliggör:

  • Automatisering av arbetsflöden: Utveckla applikationer som autonomt kan bygga och aktivera andra program som en integrerad del av ett större arbetsflöde.
  • Modularisering av system: Strukturera komplexa applikationer i mindre, självständiga moduler som kan kommunicera och samverka med varandra.
  • Utveckling av tillägg: Skapa plugin-moduler eller tillägg som utökar funktionaliteten hos befintliga applikationer genom att startas från en överordnad applikation.

Denna handledning kommer att vägleda dig genom olika metoder för att kompilera och köra Java-program inifrån andra Java-applikationer.

1. Användning av Runtime.getRuntime().exec()

Den vanligaste strategin för att exekvera externa kommandon, inklusive Java-program, är metoden Runtime.getRuntime().exec(). Denna metod initierar en ny process och kör den med ett specificerat kommando.

Exempel:


public class StartaJavaProgram {
    public static void main(String[] args) {
        try {
            // Kommando för att initiera ny process
            String kommando = "javac MinAnnanProgram.java && java MinAnnanProgram";

            // Starta processen
            Process process = Runtime.getRuntime().exec(kommando);

            // Fånga processens output
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }

            // Stäng ner processen
            process.destroy();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

I detta exempel kompileras först filen MinAnnanProgram.java och sedan aktiveras den resulterande .class-filen. Applikationens output fångas upp, vilket i detta fall är utskriften från MinAnnanProgram.

Viktiga punkter att överväga:

  • Runtime.getRuntime().exec() är en kraftfull metod, men den kan vara känslig för fel om processhanteringen inte utförs noggrant.
  • Använd BufferedReader och InputStreamReader för att korrekt läsa processens utdata.
  • Se till att avsluta processen när den är klar för att frigöra resurser.

2. Användning av ProcessBuilder

ProcessBuilder är en mer anpassningsbar klass för att initiera och hantera processer. Den tillåter definiering av mer komplexa kommandon och hantering av miljövariabler.

Exempel:


public class StartaJavaProgram {
    public static void main(String[] args) {
        try {
            // Definiera kommandot
            ProcessBuilder processBuilder = new ProcessBuilder("javac", "MinAnnanProgram.java", "&&", "java", "MinAnnanProgram");

            // Konfigurera miljövariabler
            Map<String, String> miljo = processBuilder.environment();
            miljo.put("MIN_VARIABEL", "vissVärde");

            // Starta processen
            Process process = processBuilder.start();

           // Fånga processens output (identiskt med tidigare)


        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

I detta exempel skapas kommandot med ProcessBuilder och en miljövariabel, MIN_VARIABEL, sätts till värdet vissVärde.

Fördelar med att använda ProcessBuilder:

  • Mer flexibel kommandohantering.
  • Möjlighet att definiera miljövariabler för processen.
  • Bättre hantering av fel och undantag.

3. Användning av Java-bibliotek för programkörning

Det finns flera Java-bibliotek som är specifikt konstruerade för att initiera andra program. Dessa bibliotek förenklar processen och tillhandahåller avancerade funktioner. Några av dessa bibliotek inkluderar:

  • Apache Commons Exec: Ett kraftfullt bibliotek för att köra kommandon och hantera processer.
  • JSch: Ett SSH-bibliotek för att exekvera kommandon på fjärrservrar via SSH. Läs mer om JSch.
  • Apache Ant: Ett verktyg för hantering av byggprocesser, inklusive möjligheten att köra andra Java-program. Läs mer om Apache Ant.

Exempel med Apache Commons Exec:


public class StartaJavaProgram {
    public static void main(String[] args) {
        try {
            // Skapa kommando
            CommandLine commandLine = new CommandLine("javac");
            commandLine.addArgument("MinAnnanProgram.java");

            // Utför kommandot
            DefaultExecutor executor = new DefaultExecutor();
            int exitValue = executor.execute(commandLine);

            // Kontrollera lyckat resultat
            if (exitValue == 0) {
                System.out.println("Kompilering genomförd.");
            } else {
                System.err.println("Kompilering misslyckades.");
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

I detta exempel används Apache Commons Exec för att konstruera och exekvera kommandot som kompilerar filen MinAnnanProgram.java.

4. Användning av JavaFX för att starta program i separat tråd

Om du behöver starta ett Java-program i en separat tråd, kan JavaFX användas för att hantera användargränssnittet.

Exempel:


import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class StartaJavaProgram extends Application {

    @Override
    public void start(Stage primaryStage) {
        // Skapa textruta för processens output
        TextArea outputArea = new TextArea();
        outputArea.setEditable(false);

        // Skapa knapp för att starta program
        Button startButton = new Button("Starta program");
        startButton.setOnAction(event -> {
            // Skapa ny tråd för att starta programmet
            Task<Void> task = new Task<>() {
                @Override
                protected Void call() throws Exception {
                    // Kommando för att starta programmet
                    Process process = Runtime.getRuntime().exec("java MinAnnanProgram");

                    // Fånga upp processens utdata
                    BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
                    String line;
                    while ((line = reader.readLine()) != null) {
                        updateMessage(line);
                    }
                    return null;
                }

                // Uppdatera textrutan med output
                protected void updateMessage(String message) {
                    Platform.runLater(() -> outputArea.appendText(message + "\n"));
                }
            };

            // Starta tråden
            new Thread(task).start();
        });

        // Lägg till element i layouten
        VBox root = new VBox(startButton, outputArea);
        Scene scene = new Scene(root, 400, 300);
        primaryStage.setTitle("Starta Java-program");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Här skapas en knapp som startar en separat tråd för att köra programmet. Klassen Task används för att hantera processens output och metoden Platform.runLater() uppdaterar gränssnittet i korrekt tråd.

5. Användning av Java Reflection

Java Reflection möjliggör dynamisk åtkomst till klasser och metoder under körning. Det kan användas för att ladda och exekvera kompilerade .class-filer.

Exempel:


import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

public class StartaJavaProgram {

    public static void main(String[] args) throws Exception {
        // Hämta sökväg till kompilerad .class-fil
        String classPath = "sökväg/till/MinAnnanProgram.class";

        // Skapa klassladdare
        URLClassLoader classLoader = new URLClassLoader(new URL[] { new File(classPath).toURI().toURL() });

        // Ladda klassen
        Class<?> annanProgramKlass = classLoader.loadClass("MinAnnanProgram");

        // Hämta main()-metoden
        Method mainMethod = annanProgramKlass.getMethod("main", String[].class);

        // Starta main()-metoden
        mainMethod.invoke(null, (Object) new String[] {});
    }
}

Detta exempel demonstrerar hur Reflection används för att ladda MinAnnanProgram.class och köra dess main()-metod.

Viktigt att överväga:

  • Reflection är kraftfullt men kan vara långsamt och svårt att felsöka.
  • Kontrollera att sökvägen till .class-filen är korrekt.

Sammanfattning

Möjligheten att köra Java-program från en annan Java-applikation ger dig mångsidiga verktyg för att bygga komplexa och flexibla applikationer. Metoder som Runtime.getRuntime().exec(), ProcessBuilder, Java-bibliotek, JavaFX och Java Reflection kan användas för att uppnå detta.

Val av metod beror på de specifika behoven och kraven på din applikation. Aspekter som prestanda, säkerhet och felhantering bör beaktas när du väljer metod.

Vanliga Frågor (FAQ)

1. Kan ett program köras utan att först kompilera det?

Nej, Java-program måste kompileras. Kompileringen omvandlar källkoden till bytekod, vilken Java Virtual Machine (JVM) kan läsa och exekvera.

2. Hur kan man få utdata från ett program som körs från ett annat program?

Använd BufferedReader och InputStreamReader för att läsa data från en process startad med Runtime.getRuntime().exec() eller ProcessBuilder.

3. Hur skickar jag indata till ett program som körs från ett annat program?

Indata kan skickas via att ändra inmatningsströmmen (InputStream) för processen.

4. Hur hanteras fel som inträffar under exekvering?

Fel hanteras med try-catch-block som fångar upp exceptions under körning.

5. Hur kan processens ID (PID) hämtas?

Använd Process.getProcessId() för att få processens ID.

6. Hur kör jag ett program i bakgrunden?

ProcessBuilder.redirectErrorStream(true) kan användas för att omdirigera felströmmen till standardutströmmen.

7. Skillnaden mellan Runtime.getRuntime().exec() och ProcessBuilder?

Runtime.getRuntime().exec() är enklare, medan ProcessBuilder är mer flexibel för att hantera kommandon och miljövariabler.

8. Vilka Java-bibliotek finns för processhantering?

Populära alternativ inkluderar Apache Commons Exec, JSch och Apache Ant.

9. För- och nackdelar med Java Reflection?

Java Reflection är kraftfullt men kan vara långsamt och svårt att felsöka.

10. Hur stoppar jag ett program?

Process.destroy() används för att avbryta en process.