Gradle or Maven로 빌드를 하는 이유
로컬 환경에서 개발할 때는 인텔리제이처럼 IDE의 도움을 받아서 서버를 띄울 수 있다. 하지만 실제 운영 서버에선 IDE의 도움을 빌릴 수 없고 Jar 파일을 넘겨서 실행시켜야 한다.그렇기에 빌드 툴(gradle, manve 등)을 사용해서 Jar 파일을 만들어서 운영 서버로 넘겨서 그 파일을 실행시켜야 한다.
멀티 모듈 구조에선 Gradle 관련 수정을 해야하는 부분( tasks.bootJar, tasks.jar )이 있는데 이를 한번 살펴보자!
우선 원하는 프로젝트 구조를 만들자
delivery-service
ㄴ api
ㄴ db
api는 db의 클래스와 메소드들을 알 수 있도록 설정하기 (의존성 추가)
api 모듈 추가하기
root 디렉토리에서 새로운 모듈을 만들면 settings.gradle(delivery-service)에 include='api'가 추가되면서Gradle에서도 api모듈이 추가된 것을 확인할 수 있다.
db 모듈 추가하기
같은 방법으로 db 모듈도 추가하면 settings.gradle(delivery-service)에 include='db'가 추가된다.
그러면 원했던 멀티모듈 프로젝트 구조가 되었다.
api 모듈에 db 모듈 의존성 추가하기 (implementation project(':db'))
여기서 추가로 해야하는 건 api 모듈에서 db 모듈을 사용할 수 있도록 설정해야한다는 점이다.
build.gradle(:api)에서 project() 키워드를 사용해서 db 모듈 의존성을 추가할 수 있다.
implementation project(':db')
단, implementation을 사용했기에 db 모듈에서 사용하는 의존성 라이브러리 등은 직접적으로 api에서 사용할 순 없다.
이에 관한 내용은 다음 블로그 글을 보면 이해할 수 있다.
build.gradle
부모 프로젝트는 아무런 소스코드를 가지고 있지 않기에,
빌드를 했을 때 어떠한 Jar파일도 생성되지 않도록 하고 싶다.
bootJar와 jar 둘 다 { enabled = false }로 설정해서 아무런 Jar파일이 만들어지지 않도록 했다.
allprojects
"자식 프로젝트를 다 사용하겠어!" 라는 의미
bootJar, jar 추가 설명
Gradle 빌드 시스템을 사용하는 프로젝트에서 build 디렉토리는 빌드 과정에서 생성되는 파일들이 저장되는 곳이다.
여기에는 컴파일된 클래스 파일, 실행 가능한 jar 파일(빌드 구성에 따라), 문서화 파일, 리포트 파일 등이 생성된다.
jar { enabled = false }와 같이 설정하면 Gradle은 jar 태스크를 실행하지 않으므로, build/libs 디렉토리 내에는 jar 파일이 생성되지 않는다.
마찬가지로, bootJar { enabled = false } 설정은 Spring Boot 프로젝트의 실행 가능한 jar 파일 생성을 비활성화한다.
해당 설정은 빌드 프로세스에 영향을 주기에 필요없는 빌드 작업을 하지 않도록 build.gralde에서 설정하는 것이 중요하다.
setting.gradle
include를 통해 자식 패키지를 가져오는 것을 확인할 수 있다.
build.gradle(:api)
부모 스프링버전을 따라가게끔 하고 싶다면 따로 version을 명시하지 않는다.
bootJar와 plainJar
api-1.0-SNAPSHOT.jar (= bootJar) : 스프링부트 빌드 시 기본으로 생기며, 스프링부트가 실행될 수 있게 패키징된 파일
api-1.0-SNAPSHOT-plain.jar: 자바에서 패키징했을 때 생성되는 파일
java -jar로 실행하면 bootJar는 스프링부트가 실행된다.
plain jar를 실행하면?
이렇게 나오는 이유는 plain jar의 경우 스프링부트로 패키징된 것이 아닌, 단순 해당 프로젝트 안에 있는 자바 클래스들이 패키징 된 것이다. 즉, 외부에서 참고하고자 하는 라이브러리 Jar라고도 할 수 있다.
api 모듈의 경우는 스프링부트로만 실행하고자 하기에 bootJar만 필요할 뿐 plainJar는 필요가 없다.
따라서 build.gralde(:api)에다가 bootJar만 생성되게끔 설정한다.
그러면 이제 build를 clean하면 된다.
방법1. terminal에서 명령어로 실행
terminal에선 gradlew clean (window)
방법2. Gradle -> Tasks -> build -> clean GUI에서 실행
build.gradle(:db)
이번엔 반대로 db모듈에선 스프링부트로 실행시키지 않고 엔티티만 정의할 예정이다.
build.gradle(:db)에서 아까와는 반대로 스프링부트를 실행시키는 bootJar는 생성되지 않게하고 plainJar만 생성되게끔 설정을 적용했다.
최종 빌드 결과
api - build - libs에는 bootJar만 있고
db - build - libs에는 plainJar만 있는 것을 확인할 수 있다.
참고사항
인테리제이의 모듈 생성을 새 모듈이 아닌 Spring Initializr로 생성하면 자동으로 settings.gradle 파일이 생긴다.
settings.gradle 파일은 루트에서만 관리하게끔 하기 위해 하위 모듈에선 settings.gradle 파일은 다 삭제하자!
만약 하위 모듈에 있다면? Gradle은 하위 모듈의 settings.gradle 파일을 우선순위로 읽게 되기에,
루트 프로젝트에서 관리하기가 어려워지기 때문이다.
하나의 예시를 들어보려고 한다.
상황 : module-common을 module-api에서 사용하기 위해 dependency를 설정하려고 한다.
그렇기에 우선 module-api에다가 implementation project로 common 모듈을 추가했다.
하지만 Gradle build를 새로 하니까 에러가 난다.
에러 이유는 앞서 말했듯 module-api의 settings.gradle을 우선순위로 gradle 빌드를 하게되는데 해당 settings.gradle에선
common 모듈 관련 include 된 것이 없기에 발생한다.
따라서 settings.gradle을 루트 프로젝트에서 관리하게끔 하여 이러한 상황을 만들지 않도록 하면서
멀티모듈 프로젝트를 설정하는 방향으로 프로젝트를 초기 셋팅하자!
PrepareKotlinBuildScriptModel Error 발생 시 해결
tasks.register("prepareKotlinBuildScriptModel") {}
위 에러 발생 시 bulid.gralde에 위의 코드 추가하면 해결된다.
tasks.bootJar와 tasks.jar
두 옵션 다 기본 옵션 값은 true다. 만약 두 옵션 다 true로 gradle 빌드를 하면? xxx.jar (bootJar)xxx-plain.jar (jar)두 개의 파일이 생성된다.
bootJar와 jar의 차이는 jar로 생성된 빌드 파일(xxx-plain.jar)의 경우 dependency를 갖고 있지 않는다.즉, 클래스와 리소스만 포함하고 있어서 plain의 파일은 서버를 실행시킬 수 없다.
따라서 각 모듈에 따라 적절하게 옵션 값을 수정해서 빌드를 해야한다.
빌드 예시
./gradlew clean :module-api:buildNeeded --stacktrace --info --refresh-dependencies -x test
실행 예시 (build libs에서)
java -jar module-api-0.0.1-SNAPSHOT.jar
'Spring' 카테고리의 다른 글
[Spring] Swagger (0) | 2024.03.19 |
---|---|
[Spring] 멀티모듈 (2) - 멀티모듈 프로젝트 진행시 생길 수 있는 이슈들 정리(feat. implementation, configuration, component scan) (0) | 2024.03.19 |
(임시)[Spring] Spring 비동기 끄적이는중... (1) | 2024.03.18 |
[Spring] 스프링 부트 Dependency Versions 확인하기 (0) | 2023.10.03 |
[Spring] Gradle dependency - implementation과 api 차이 (1) | 2023.03.09 |