포스트

[JAVA] 외부 프로세스 실행

환경

javaspringbootpython
17.0.63.1.03.11.2

java.lang.ProcessBuilder

외부 프로세스 객체는 java.lang.Runtime 클래스, java.lang.ProcessBuilder 클래스 사용할 수 있다.

하지만 이러한 사용법은 java.lang.Process 클래스의 API 문서에 문제법이 나와있다.

Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, or even deadlock.
일부 네이티브 플랫폼은 표준 입력 및 출력 스트림을 위한 제한된 버퍼 크기만 제공하기 때문에, 입력 스트림을 즉시 쓰거나 하위 프로세스의 출력 스트림을 읽지 못하면 하위 프로세스가 차단되거나 심지어 교착 상태에 빠질 수 있습니다.

문제를 해결하려면 여러 개의 전용 클래스를 생성하거나 오픈소스 라이브러리 zt-exec를 사용한다.


zt-exec 사용법

Spring 프로젝트 dependency를 추가한다

Maven

1
2
3
4
5
6
7
pom.xml

<dependency>
    <groupId>org.zeroturnaround</groupId>
    <artifactId>zt-exec</artifactId>
    <version>1.12</version>
</dependency>

Gradle

1
2
3
4
5
6
7
build.gradle

dependencies {
    // 다른 의존성들...
    
    implementation 'org.zeroturnaround:zt-exec:1.12'
}

의존성을 추가한 후에는 Gradle을 동기화하여 변경 사항을 적용해야 한다. IDE(통합 개발 환경)에서는 보통 Gradle 동기화를 자동으로 수행하거나 “Sync Project” 버튼을 클릭하여 수동으로 동기화할 수 있다.

적용 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import org.zeroturnaround.exec.ProcessExecutor;
import org.zeroturnaround.exec.ProcessResult;
import java.util.concurrent.TimeoutException;

public class PythonExecutionExample {
    public static void main(String[] args) {
        try {
            ProcessResult result = new ProcessExecutor()
                    .command("python", "파일경로.py", "인자1", "인자2")
                    .readOutput(true) // 프로세스 출력 읽기 설정
                    .execute();

            int exitValue = result.getExitValue();
            String output = result.outputUTF8();

            // python 결과 출력
            System.out.println("Exit Value: " + exitValue);
            System.out.println("Output: " + output);
        } catch (InterruptedException | TimeoutException | java.io.IOException e) {
            e.printStackTrace();
        }
    }
}

공식 예제 몇가지

  • 반환 및 출력 없음
1
new ProcessExecutor().command("java", "-version").execute();

  • 종료 코드 반환
  • 출력 없음
1
2
int exit = new ProcessExecutor().command("java", "-version")
                  .execute().getExitValue();

  • 출력을 UTF8로
1
2
3
String output = new ProcessExecutor().command("java", "-version")
                  .readOutput(true).execute()
                  .outputUTF8();    

  • 출력을 로거(logger)로 전달
1
2
new ProcessExecutor().command("java", "-version")
      .redirectOutput(Slf4jStream.of(LoggerFactory.getLogger(getClass().getName() + ".MyProcess")).asInfo()).execute();

  • 출력을 로거(logger)로 전달(이전 보다 짧은)
1
2
new ProcessExecutor().command("java", "-version")
      .redirectOutput(Slf4jStream.of("MyProcess").asInfo()).execute();

더 많은 예제는 공식 github에서
https://github.com/zeroturnaround/zt-exec

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.