Notice
Recent Posts
Link
Tags
- spring
- PYTHON
- spring security 6
- @transactional
- 데이터베이스
- java
- spring mvc
- 자바
- select
- 스프링
- SSL
- jpa
- session
- 1차원 배열
- 프로그래머스
- join
- Docker
- 스프링부트
- Django
- AWS
- nginx
- ORM
- spring boot
- sql
- 문자열
- DI
- Git
- string
- springboot
- mysql
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Archives
개발하는 자몽
Java에서 외부 프로그램 실행하기 (zt-exec) 본문
프로젝트를 진행하면서 Java 환경에서 Python 프로그램을 실행해야 할 일이 생겼다. 해본 적이 없어서 할 수 있는지가 걱정이었는데 역시 안될 건 없다.
종류
일단 외부 프로그램을 실행할 때 쓰이는 방법들을 찾아보았다.
- JSR-233 Scripting Engine
- Jython
- ProcessBuilder
- Apache Common Exec(thrid-party lib)
- ZT Process Executor
- HTTP (python server)
JSR-233 Scripting Engine
- Java 6 부터 지원
- set of scripting APIs
- `CLASSPATH`에 `Jython`이 있어야 함
- Jython의 경우 파이썬 라이브러리를 한정적으로 사용하게 됨
Jython
- 자바 코드에 파이썬 코드를 직접적으로 임베딩할 수 있음
- 자바 코드에 파이썬 코드가 섞여서 유지보수가 어려워짐
- Jython의 경우 파이썬 라이브러리를 한정적으로 사용하게 됨
ProcessBuilder
- 자바에서 외부 프로그램을 실행하고 관리하기 위한 도구
- 작성된 파이썬 파일을 실행하는 방식
- `assumption` PATH 변수를 통해 파이썬을 사용할 수 있어야 함
- 안전하게 스트림을 처리하려면 3~4개 이상의 전용 클래스를 구현해야 함
- "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."
Apache Common Exec
- ProcessBuilder 코드와 비슷함
- 작성된 파이썬 파일을 실행하는 방식
- 일관된 API로 폭넓은 OS를 지원하는 것이 주요 철학
ZT Process Executor
- `ProcessBuilder`, `common-exec` 기능 사용 가능
- Improved handling of stream
- One liners to get process output into a String
- Improved logging with SLF4J API
- only 3rd-party dependency is SLF4J
- 🔗깃허브 주소
HTTP
python -m http.server 9000
또는 Flask나 Django를 이용하여 HTTP 통신을 하는 방법
나는 이 중에서 `ZT Process Executor`를 선택했다. 제공하는 기능이 폭넓고 예제 코드도 나와있어서 좋았다. 또한 사용하기 위해 어떤 추가적인 라이브러리 등이 필요하지 않다는 점이 좋았다.
ZT Process Executor
실행될 파이썬 프로그램은 파일을 인자로 받으며, 자바는 파이썬을 호출하고 나서 해당 결과를 파싱 하여 저장한다.
...
public class FileHandler {
private final FileService fileService;
...
public returnType pythonExecutor(MultipartFile file) {
File saveFile = fileService.saveFile(file);
String savedPath = saveFile.getSavedPath();
final String pyPath = "...";
String[] commands = {"python", pyPath, savedPath};
String output = null;
//ZT Process Executor를 이용한 python 파일 호출
try {
output = new ProcessExecutor().command(commands)
.readOutput(true).execute()
.outputUTF8();
} catch (IOException | InterruptedException | TimeoutException e) {
log.error("Process Executor Error occur: ", e);
throw new RuntimeException(e);
}
// 결과 파싱
JSONObject result = parseJson(output);
String field = result.get("원하는 필드"); //이런식으로 파싱한 결과의 필드를 꺼낼 수 있음
...
}
private JSONObject parseJson(String output) {
final String jsonOuterKey = "field";
JSONParser parser = new JSONParser();
JSONObject object;
try {
object = (JSONObject) parser.parse(output);
} catch (ParseException e) {
log.error("JSON Parse Error occur: ", e);
throw new RuntimeException(e);
}
return (JSONObject) object.get(jsonOuterKey);
}
}
`parseJson` 메서드에서 `jsonOuterKey`는 이런 경우를 위함이다. 겉에 아무것도 없다면 바로 꺼내면 된다.
"field" : {
"aaa": ...,
...
}
자세한 ZT Process Executor 사용법은 깃허브 링크를 참고!
'Java' 카테고리의 다른 글
[Gradle] gradle build와 gradle bootJar의 차이 (0) | 2024.09.06 |
---|---|
[Java] new Integer와 Integer.valueOf()의 차이점 (0) | 2024.08.11 |
[TIL / JPA] 데이터베이스 스키마 자동 생성, UNIQUE 제약 조건 관련 TIL (0) | 2024.06.30 |
[TIL / JPA] 영속성 컨텍스트 (0) | 2024.06.29 |
Collections, Collector, stream의 함수 (0) | 2023.05.03 |
Comments