Programing

Java 프로그램에서 다른 jar 실행

crosscheck 2020. 8. 17. 08:02
반응형

Java 프로그램에서 다른 jar 실행


A.jar, B.jar라는 이름의 간단한 Java 응용 프로그램을 여러 개 작성했습니다.

이제 사용자가 버튼 A를 눌러 A.jar을 실행하고 버튼 B를 눌러 B.jar를 실행할 수 있도록 GUI Java 프로그램을 작성하고 싶습니다.

또한 GUI 프로그램에서 런타임 프로세스 세부 정보를 출력하고 싶습니다.

어떠한 제안?


내가 올바르게 이해하면 Java GUI 응용 프로그램 내부에서 별도의 프로세스에서 jar를 실행하려는 것으로 보입니다.

이를 위해 다음을 사용할 수 있습니다.

// Run a java app in a separate system process
Process proc = Runtime.getRuntime().exec("java -jar A.jar");
// Then retreive the process output
InputStream in = proc.getInputStream();
InputStream err = proc.getErrorStream();

항상 프로세스의 출력을 버퍼링하는 것이 좋습니다.


.jar는 실행 가능하지 않습니다. 클래스를 인스턴스화하거나 정적 메서드를 호출합니다.

편집 : JAR을 만드는 동안 Main-Class 항목을 추가합니다.

> p.mf (p.mf의 내용)

메인 클래스 : pk.Test

>Test.java

package pk;
public class Test{
  public static void main(String []args){
    System.out.println("Hello from Test");
  }
}

Process 클래스와 메서드를 사용하십시오.

public class Exec
{
   public static void main(String []args) throws Exception
    {
        Process ps=Runtime.getRuntime().exec(new String[]{"java","-jar","A.jar"});
        ps.waitFor();
        java.io.InputStream is=ps.getInputStream();
        byte b[]=new byte[is.available()];
        is.read(b,0,b.length);
        System.out.println(new String(b));
    }
}

도움이 되었기를 바랍니다:

public class JarExecutor {

private BufferedReader error;
private BufferedReader op;
private int exitVal;

public void executeJar(String jarFilePath, List<String> args) throws JarExecutorException {
    // Create run arguments for the

    final List<String> actualArgs = new ArrayList<String>();
    actualArgs.add(0, "java");
    actualArgs.add(1, "-jar");
    actualArgs.add(2, jarFilePath);
    actualArgs.addAll(args);
    try {
        final Runtime re = Runtime.getRuntime();
        //final Process command = re.exec(cmdString, args.toArray(new String[0]));
        final Process command = re.exec(actualArgs.toArray(new String[0]));
        this.error = new BufferedReader(new InputStreamReader(command.getErrorStream()));
        this.op = new BufferedReader(new InputStreamReader(command.getInputStream()));
        // Wait for the application to Finish
        command.waitFor();
        this.exitVal = command.exitValue();
        if (this.exitVal != 0) {
            throw new IOException("Failed to execure jar, " + this.getExecutionLog());
        }

    } catch (final IOException | InterruptedException e) {
        throw new JarExecutorException(e);
    }
}

public String getExecutionLog() {
    String error = "";
    String line;
    try {
        while((line = this.error.readLine()) != null) {
            error = error + "\n" + line;
        }
    } catch (final IOException e) {
    }
    String output = "";
    try {
        while((line = this.op.readLine()) != null) {
            output = output + "\n" + line;
        }
    } catch (final IOException e) {
    }
    try {
        this.error.close();
        this.op.close();
    } catch (final IOException e) {
    }
    return "exitVal: " + this.exitVal + ", error: " + error + ", output: " + output;
}
}

If the jar's in your classpath, and you know its Main class, you can just invoke the main class. Using DITA-OT as an example:

import org.dita.dost.invoker.CommandLineInvoker;
....
CommandLineInvoker.main('-f', 'html5', '-i', 'samples/sequence.ditamap', '-o', 'test')

Note this will make the subordinate jar share memory space and a classpath with your jar, with all the potential for interference that can cause. If you don't want that stuff polluted, you have other options, as mentioned above - namely:

  • create a new ClassLoader with the jar in it. This is more safe; you can at least isolate the new jar's knowledge to a core classloader if you architect things with the knowledge that you'll be making use of alien jars. It's what we do in my shop for our plugins system; the main application is a tiny shell with a ClassLoader factory, a copy of the API, and knowledge that the real application is the first plugin for which it should build a ClassLoader. Plugins are a pair of jars - interface and implementation - that are zipped up together. The ClassLoaders all share all the interfaces, while each ClassLoader only has knowledge of its own implementation. The stack's a little complex, but it passes all tests and works beautifully.
  • use Runtime.getRuntime.exec(...) (which wholly isolates the jar, but has the normal "find the application", "escape your strings right", "platform-specific WTF", and "OMG System Threads" pitfalls of running system commands.

The following works by starting the jar with a batch file, in case the program runs as a stand alone:

public static void startExtJarProgram(){
        String extJar = Paths.get("C:\\absolute\\path\\to\\batchfile.bat").toString();
        ProcessBuilder processBuilder = new ProcessBuilder(extJar);
        processBuilder.redirectError(new File(Paths.get("C:\\path\\to\\JavaProcessOutput\\extJar_out_put.txt").toString()));
        processBuilder.redirectInput();
        try {
           final Process process = processBuilder.start();
            try {
                final int exitStatus = process.waitFor();
                if(exitStatus==0){
                    System.out.println("External Jar Started Successfully.");
                    System.exit(0); //or whatever suits 
                }else{
                    System.out.println("There was an error starting external Jar. Perhaps path issues. Use exit code "+exitStatus+" for details.");
                    System.out.println("Check also C:\\path\\to\\JavaProcessOutput\\extJar_out_put.txt file for additional details.");
                    System.exit(1);//whatever
                }
            } catch (InterruptedException ex) {
                System.out.println("InterruptedException: "+ex.getMessage());
            }
        } catch (IOException ex) {
            System.out.println("IOException. Faild to start process. Reason: "+ex.getMessage());
        }
        System.out.println("Process Terminated.");
        System.exit(0);
    }

In the batchfile.bat then we can say:

@echo off
start /min C:\path\to\jarprogram.jar

If you are java 1.6 then the following can also be done:

import javax.tools.JavaCompiler; 
import javax.tools.ToolProvider; 

public class CompilerExample {

    public static void main(String[] args) {
        String fileToCompile = "/Users/rupas/VolatileExample.java";

        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

        int compilationResult = compiler.run(null, null, null, fileToCompile);

        if (compilationResult == 0) {
            System.out.println("Compilation is successful");
        } else {
            System.out.println("Compilation Failed");
        }
    }
}

참고URL : https://stackoverflow.com/questions/1320476/execute-another-jar-in-a-java-program

반응형