티스토리 뷰

  • 현업을 경험해보기 전에는 프로젝트가 비교적 단순했기 때문에 gradle 설정도 간단했고 멀티 프로젝트라는 개념도 눈에 들어오지 않았습니다.
  • 이번에 맡게된 프로젝트를 뜯어보면서도 어떤 구조로 설계되었는지, 어떠한 로직들로 구성되었는지를 파악하는 데에만 집중하였고 application.yml 이나 build.gradle 설정들은 신경쓰지 못했던 것 같습니다.
  • 중요하지만 간과하기 쉬운 부분을 다지는 의미에서 직접 멀티 모듈 프로젝트를 구성해보며 해당 내용을 정리하게 되었습니다.

 

프로젝트 구성

  • multi-project(root 프로젝트. 전역 설정을 담당)
    • module-boot(프로젝트 부팅을 담당)
    • module-domain(엔티티)
    • module-controller(컨트롤러)

  • 전역 설정을 담당하는 multi-project를 구성하면서 전역에서 함께 사용할 디펜던시를 추가해주었습니다.

  • 그러면 처음에는 위와 같은 구조로 프로젝트가 생성이 됩니다.

  • 그리고 multi-project 하위에 각 모듈들을 추가해줍니다.

  • 그러면 각 모듈들도 루트 프로젝트와 마찬가지로 gradle폴더와 build.gradle, settings.gradle을 갖게 됩니다. 우선 이 파일들이 어떤 역할을 하는지 알아보아야 할 것 같습니다.

 

build.gradle / settings.gradle / gradle.wrapper

build.gradle

  • 프로젝트의 의존관계나 태스크를 정의할 때 사용됩니다. 일반적으로 gradle 프로젝트는 이 파일만으로 빌드가 가능합니다.

 

settings.gradle

  • settings.gradle은 빌드에 포함될 프로젝트들을 설정하는 스크립트입니다. 빌드에 참여하는 프로젝트들의 계층 구조를 정의하고 구성하는 데 필요한 설정을 작성합니다.
rootProject.name = 'multi-project'
include 'module-boot'
include 'module-domain'
include 'module-controller'
  • 기본적으로 rootProject.name = '[프로젝트 이름]' 이 입력되어서 생성이 되는데요. 하위 프로젝트는 include 를 통해 정의할 수 있습니다.
  • gradle은 빌드가 실행될 때마다 settings.gradle 파일을 찾아, 해당 파일을 참고하여 빌드를 초기화합니다.
  • 만약 settings.gradle 파일이 없는 디렉토리에서 gradle을 실행하는 경우 다음 순서를 따릅니다.
  1. 우선 상위 디렉토리에서 찾습니다.
  2. 상위 디렉토리에서 찾았다면, 현재 프로젝트가 multi-project 빌드에 참여하는지 확인합니다. 참여한다면 multi-project로 빌드됩니다.
  3. 만약 찾지 못했다면 단일 프로젝트로 빌드됩니다.

 

gradle.wrapper

  • gradle 프로젝트를 빌드하고 실행하기 위해서는 로컬 컴퓨터에 해당 프로젝트와 동일한 버전이 존재해야 합니다. 만약 이들이 일치하지 않는다면, 당연하게도 오류가 발생합니다.
  • 따라서, 항상 사용하려는 프로그램의 gradle 버전과 동일하게 gradle을 설치해주어야 하는데 이는 굉장히 비효율적인 방법입니다.
  • gradle Wrapper는 지정된 버전의 gradle을 실행하는 스크립트로, 필요한 경우 gradle 배포판(distribution)을 배포 서버에서 다운로드하여 위 과정들을 자동화해줍니다.
distributionBase=GRADLE_USER_HOME  
distributionPath=wrapper/dists  
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip  
networkTimeout=10000  
validateDistributionUrl=true  
zipStoreBase=GRADLE_USER_HOME  
zipStorePath=wrapper/dists
  • gradle-wrapper.properties를 보면 위와 같은 코드를 볼 수가 있는데 distributionUrl에 지정되어 있는 gradle버전을 사용하여 빌드를 하게 됩니다.

 

gradle-wrapper.jar

  • gradle 배포판을 다운로드하는 코드가 포함된 JAR 파일입니다.

 

gradle-wrapper.properties

  • 현재 프로젝트와 호환되는 Gradle 배포판의 버전을 포함하여 Gradle Wrapper의 런타임 속성이 포함됩니다.

 

gradlew, gradle.bat

  • wrapper를 통해 빌드를 실행하는 스크립트로 gradlew은 맥과 리눅스용, gradle.bat은 윈도우용 스크립트입니다.
  • gradle 빌드는 항상 Wrapper를 통해 실행하는 것이 권장됩니다.
  • gradle build를 사용하면 로컬에 설치된 gradle과 java를 기준으로 build하지만, ./gradlew build를 실행하면 build.gradle파일에 정의한 내용을 기준으로 build되기 때문에 로컬 환경과 관계없이 프로젝트를 빌드할 수 있습니다.
  • wrapper는 gradlew를 통해 다음과 같이 사용할 수 있습니다.

./gradlew [태스크 이름]

  • 위는 gradle [태스크 이름]과 동일한 역할을 하는데, 컴퓨터에 설치된 gradle이 아닌 wapper를 사용한다는 것이 차이점입니다.

gradle.bat은 다음과 같이 사용할 수 있습니다.

gradlew.bat [태스트 이름]

  • settings.gradle 같은 경우는 루트 프로젝트에서 하위 프로젝트를 정의하는 데 사용할 수 있으므로 하위 모듈들은 갖고 있을 필요가 없을 것입니다.
  • wrapper 또한 루트 프로젝트만 갖고 있어야 되겠지요! 따라서 필요한 파일들만 남기고 모두 삭제해줍니다.

 

전역 build.gradle 설정

// multi-project의 build.gradle

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.2.3'
    id 'io.spring.dependency-management' version '1.1.4'
}

// 전역 모듈은 Main Class() 가 존재하지 않으므로 bootJar를 만들지 않음
bootJar.enabled = false

// 모든 프로젝트에 공통으로 적용할 사항.
allprojects {
    group = 'org.example'
    version = '0.0.1-SNAPSHOT'

    repositories {
        mavenCentral()
    }
}

// 하위 프로젝트에 공통으로 적용할 사항
subprojects {
    apply plugin: 'java'
    apply plugin: 'java-library'
    apply plugin: 'org.springframework.boot'
    apply plugin: 'io.spring.dependency-management'

    java {
        sourceCompatibility = '17'
    }

    configurations {
        compileOnly {
            extendsFrom annotationProcessor
        }
    }

    dependencies {
        implementation 'org.springframework.boot:spring-boot-starter-web'
        compileOnly 'org.projectlombok:lombok'
        annotationProcessor 'org.projectlombok:lombok'
        testImplementation 'org.springframework.boot:spring-boot-starter-test'
    }

    tasks.withType(Test).tap {
        configureEach {
            enabled = false
        }
    }

    // 컨트롤러와 도메인 모듈은 Main Class()를 사용하지 않으므로 bootJar 작업을 비활성화!
    project(':module-controller') {
        bootJar.enabled = false
    }

    project(':module-domain') {
        bootJar.enabled = false
    }
}
  • 전역 설정으로 하위 프로젝트에 공통으로 롬복을 포함한 디펜던시들을 정의해주었습니다.

 

  • module-domain 에는 따로 디펜던시를 설정하지 않았지만 domain 모듈에서 롬복을 사용할 수 있는 모습입니다.

 

마무리

  • 멀티 프로젝트를 구성하는 것 자체는 어렵지 않았지만 여러가지 생각할 거리들이 많았습니다.
  • 하위 모듈간 의존을 위한 implements나 api project와 같은 키워드도 알아볼 필요성을 느꼈고
  • 전체적인 프로젝트 구성을 어떻게 하느냐에 따라 설계 방식도 많이 달라질 것 같다는 생각을 하였습니다.
  • 그리고 의존성을 주입하는 것도 전역에서 주입을 할 것인지 특정 모듈에만 주입을 할 것인지에 대한 고민도 필요한 것 같습니다.

관련 자료

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/09   »
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
글 보관함