스프링 부트 멀티모듈을 환경에서 발생했던 Boot Jar 설정 오류를 다뤄보고자 한다. root 디렉터리의 주석 부분을 추가하여 문제를 해결할 수 있었다. 오류 발생 시점의 build.gradle 파일은 아래와 같다.
subprojects {
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
dependencies {
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
}
tasks.named('test') {
useJUnitPlatform()
}
// bootJar.enabled = false
}
project(':used-trading-application') {
dependencies {
implementation project(':used-trading-domain')
}
}
project(':used-trading-bootstrap') {
// bootJar.enabled = true
dependencies {
implementation project(':used-trading-domain')
implementation project(':used-trading-application')
implementation project(':used-trading-framework')
}
}
project(':used-trading-framework') {
dependencies {
implementation project(':used-trading-domain')
implementation project(':used-trading-application')
}
}
jar {
enabled = false
}
//bootJar {
// enabled = false;
//}
프로젝트의 모듈 구성은 아래와 같다.
bootstrap 모듈이 스프링부트 애플리케이션의 시작 클래스를 가지고 있는 모듈이다. 나머지 모듈들은 시작점은 없고 bootstrap에서 읽어들여 사용된다. (이걸 처음에 인지했으면 문제가 아주 빨리 해결됐을텐데,,, 이렇게 간단한 걸 몰라서 5시간을 헤멨다)
오류 내용
gradle을 통해 프로젝트를 build했을 때, 프로그램의 시작점인 bootJar를 생성하기 위한 태스크인 booJar 실행을 실패했다는 오류이다.
./gradlew clean build
> Task :bootJar FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':bootJar'.
> Error while evaluating property 'mainClass' of task ':bootJar'.
> Failed to calculate the value of task ':bootJar' property 'mainClass'.
> Main class name has not been configured and it could not be resolved from classpath
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.
BUILD FAILED in 656ms
해결 과정
root 빌드 파일의 bootJar 태스크에 프로그램 시작 클래스 명시해주기 (실패)
오류를 살펴보면 bootJar 태스크에 mainClass 프로퍼티를 추가하라고 한다.
아래처림 루트 build.gradle에 bootJar 태스크에 mainClassName 프로퍼티를 추가하여 프로그램 시작(메인 메서드를 포함하는) 클래스를 명시해 주었다.
bootJar {
launchScript()
mainClassName = 'org.flab.hyunsb.bootstrap.BootstrapApplication'
}
결과는 역시나 실패 한번에 해결되는 오류를 만난적이 언제던가,,
Build file '/Users/hyunsb/Documents/used-trading-market/build.gradle' line: 76
A problem occurred evaluating root project 'used-trading-market'.
> Could not set unknown property 'mainClassName' for task ':bootJar' of type org.springframework.boot.gradle.tasks.bundling.BootJar.
used-trading-market 모듈이 루트 모듈인데 mainClassName 프로퍼티를 설정할 수 없다고 한다.
root 모듈에서 bootJar 생성 옵션 꺼주기 (실패)
생각해보니 루트 모듈에 프로그램 시작점이 있는 것도 이상하지 않은가?! 그래서 해당 설정을 끄고 빌드해봤다. 이렇게 하면 Bootstrap 모듈을 빌드하면서 알어서 bootJar가 생길 것이라 생각했다.
./gradlew clean build
> Task :used-trading-application:bootJar FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':used-trading-application:bootJar'.
> Error while evaluating property 'mainClass' of task ':used-trading-application:bootJar'.
> Failed to calculate the value of task ':used-trading-application:bootJar' property 'mainClass'.
> Main class name has not been configured and it could not be resolved from classpath build/classes/java/main
흠 application 모듈에서 bootJar를 실패했다고 한다.
각 모듈에서 BootJar 생성 옵션 꺼주기 (실패)
일단 하라는 대로 해보자. application은 메인메서드가 없다. 따라서 bootJar 옵션을 꺼주기로 했다.
project(':used-trading-application') {
dependencies {
implementation project(':used-trading-domain')
}
bootJar.enabled = false
}
> Task :used-trading-domain:bootJar FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':used-trading-domain:bootJar'.
> Error while evaluating property 'mainClass' of task ':used-trading-domain:bootJar'.
> Failed to calculate the value of task ':used-trading-domain:bootJar' property 'mainClass'.
> Main class name has not been configured and it could not be resolved from classpath build/classes/java/ma
역시나 실패, 그런데 오류 냐용이 바뀌었다. domain 모듈에서 bootJar 태스크가 실패했다는 것! (여기서 깨달았으면 빨리 끝났을 것을,,)
모든 모듈의 BootJar 생성 옵션 꺼주기 (성공?인 줄 알았으나 실패)
사실 이때까지도 BootJar가 의미하는 바를 이해하지 못하고 오류를 수정하고 있었다. 모든 모듈에서 bootJar를 생성하지 않게 옵션을 추가해주고 clean build를 수행해봤다.
subprojects {
bootJar.enabled = false
}
BUILD SUCCESSFUL in 5s
25 actionable tasks: 25 executed
성공?! 빌드 차제는 성공했다. 자 이제 jar 파일로 프로그램을 실행시켜볼까?
그렇다. plain archive는 이전 포스팅에서 말했듯이 실행할 수 있는 파일이 아니다. 프로그램을 실행시킬 수가 없다.. 이 때 깨달았다 bootJar 태스크가 우리가 실행할 수 있는 jar 파일을 생성해준다는 것을
문제 해결: 프로그램의 시작점인 모듈에서 bootJar 생성
하나의 bootJar는 있어야 프로그램을 배포하고 실행시킬 수 있지 않겠는가 그래서 bootstrap 모듈에서 bootJar를 생성하록 설정해주었다.
// 다른 모듈은 bootJar 설정이 켜져있으면 오류가 발생하니 꺼주자
subprojects {
bootJar.enabled = false
}
// 애플리케이션 시작 모듈에서는 bootJar 옵션을 다시 명시해주어 켜주자
project(':used-trading-bootstrap') {
bootJar.enabled = true
jar.enabled = false
dependencies {
implementation project(':used-trading-domain')
implementation project(':used-trading-application')
implementation project(':used-trading-framework')
}
}
마참내! 빌드에 성공했다. 이제 실행시켜 보면
성공!
결론
오류가 발생하면 일단 원인이 무엇인지 부터 침착하게 파악하자 (잘 안되겠지만)
다른 오류가 연쇄적으로 발생하도 일단 침착하자 (본인은 화가 많이 나지만)
원인이 파악되면 해결 방법은 스스로 잘 생각할 수 있을 정도로 쉬울 것이다. (아닐 수도 있지만)
'트러블슈팅' 카테고리의 다른 글
Jackson 직렬화 내부 동작 방식으로 인한 Redis 캐시 데이터 파싱 오류 (0) | 2024.12.16 |
---|---|
테스트 더블을 직접 구현하여 발생한 이슈 (0) | 2024.05.03 |
모듈간 의존성은 있는데 소스 정보를 읽어오지 못하는 이슈 (Plain Archive의 사용처?) (1) | 2024.02.10 |
[Spring Security + JWT] 크롬과 Postman의 인증 결과가 다른현상 (0) | 2023.07.14 |
[Git] 작업이 종료 직전 브랜치를 잘못 생성한 걸 깨달았다,, (0) | 2023.06.30 |