본문 바로가기

카테고리 없음

Gradle은 어떻게 동작하는 걸까??

Multi Module을 활용한 Mono Repo로 구성된 프로젝트를 수행하다가 문득

각 모듈들이 어떻게 빌드가 되고, 어떻게 하나의 어플리케이션으로 띄워지는지 궁금해졌다

 

project
    ㄴ api
    	ㄴ...main..java...
        	ㄴApiApplication
        ㄴbuild.gradle
    ㄴ core
    	ㄴ...
        ㄴbuild.gradle
    ㄴbatch
    	ㄴ...
        ㄴbuild.gradle
        
    ㄴ gradle
        ㄴwrapper
        	ㄴgradle-wrapper.jar
            ㄴgradle-wrapper.properties
    ㄴ gradlew
    ㄴ gradlew.bat
    ㄴ build.gradle
    ㄴ settings.gradle

 

이렇게 Root Project를 기준으로 멀티 module로 구성된 프로젝트이고

여기서 각 build.gradle 과 settings.gradle 파일이

빌드과정에서 어떠한 역할을 담당하는지 궁금해졌다

 

🤔 Gradle 컨셉과 구성요소

출처 : Gradle Core Concept

 

Gradle Document에서 이야기 하는 Gradle의 주요 컨셉과 구성요소는 아래와 같다

 

👉 Project

  • Gradle에서 Project는 빌드할 수 있는 응요프로그램 혹은 라이브러리의 조각
  • Project가 한개일때는 Root Project, 2개 이상일 때는 한개의 Root Project와 N개의 Subproject들로 구성

👉 Build Script

  • Gradle에세 프로젝트를 빌드하려면 어떠한 단계들을 거쳐야하는지 알려준다
  • Build Flow를 정의한다

👉 Depenency Manager

  • 프로젝트에 필요한 외부 리소스들을 선언하고, 자동적으로 관리
  • 빌드 과정에서 Gradle이 외부 의존성들을 포함시킴

👉 Tasks

  • 코드를 컴파일하거나 테스트를 실행하는 과정의 기본 일 단위
  • Plugin과 Build Script에 정의된다
  • Intellij 같은 IDE에서는 gradle 탭을 눌렀을때 보이는 것들이 task다 (./gradlew task -all 을 통해서도 볼 수 있음)

👉 Plugins

  • Gradle 기능을 확장하고 task들을 지원

 

🤔 gradlew?? 

프로젝트 root에 gradlew가 있다면 gradle을 빌드 도구로 사용하는 프로젝트임을 나타냄

ProjectRoot
	ㄴ...
    ㄴgradle
    	ㄴwrapper
            ㄴgradle-wrapper.jar // 버전에 맞는 gradle을 서버로부타 다운받는 코드가 있는 실행파일
            ㄴgradle-wrapper.properties // 어디서 다운 받을 것인지, 파일에서 가져올 것인지
    ㄴbuild.gradle
    ㄴgradle.properties
    ㄴgradlew // Unix용 실행 스크립트
    ㄴgradlew.bat // Windows용 실행 스크립트

 

Gradle Wrapper를 실행하는 것이 gradlew 이다

gradlew를 통해서 buid를 실행하는 것을 권장한다

👉 Gradle Wrapper

로컬에서 선언된 버전의 Gradle을 호출하고, 없는 경우 Gradle 서버로부터 해당 버전에 맞는 환경을 다운로드하는 역할을 한다 

  • Gradle 버전에 맞게 빌드 환경을 표준화 가능
  • 덕분에 환경에 종속되지 않고, 어디에서나 빌드할때 동일한 환경을 갖출 수 있다
  • 개발자마다 다른 Gradle을 사용하는 경우 버전 차이로 빌드 에러가 생길수 있으므로, gradle 버전관리를 프로젝트에 종속시켜서 개발자별로 빌드 환경이 상이한 것을 방지 -> gradlew로 build 실행시, 개발자 로컬 환경의 gradle이 다른 버전이라도, gradle-wrapper에 설정된 gradle 버전으로 빌드

 

 

  1. Server로부터 설정한 버전에 따른 배포본을 다운 받고
  2. 로컬의 GRADLE_USER_HOME 환경변수에 설정된 경로에 저장하고 압축을 푼다
  3. Gradle이 Build를 시작할 때, 위의 경로에 있는 버전의 Gradle을 이용

 

gradle-wrapper를 공부하면서 왜 현재 프로젝트에서 세팅 초반에 gradle bin zip 파일을 다운받고, gradle-wrapper.properties 파일을 수정하라고 했는지 알게되었다 

 

만약 회사의 보안 문제로 Gradle을 다운받아오는 Server에 연결할 수 없다면

  • gradle 버전을 fix해놓고, 수정할 일이 없다면
  • gradle 파일을 직접 다운받아서 properties 파일을 세팅해주면 된다

 

ProjectRoot
	ㄴ...
    ㄴgradle
    	ㄴwrapper
            ㄴgradle-wrapper.jar // 버전에 맞는 gradle을 서버로부타 다운받는 코드가 있는 실행파일
            ㄴgradle-wrapper.properties // 어디서 다운 받을 것인지, 파일에서 가져올 것인지
        ㄴgradle-7.6.2-bin.zip
    ㄴbuild.gradle
    ㄴgradle.properties
    ㄴgradlew // Unix용 실행 스크립트
    ㄴgradlew.bat // Windows용 실행 스크립트
// gradle-wrapper.properties

distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=../gradle-7.6.4-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

 

distributuinUrl이 Gradle 서버인, https://services.gradle.org가 아닌 프로젝트에 폴더에 다운로드해놓은 gradle로 path로 설정

 

 

🤔 settings.gradle???

모든 Gradle의 entry point다

프로젝트의 구조에 대해서 정의되는 파일이다 -> 그렇기 때문에 위치는 Project의 Root에 위치

  • Project가 Root Project한개라면, 디렉토리를 따라가면 되어서 정의할 필요가 없으므로 해당 파일 없어도됨
  • Project가 여러개라면, Root Project와 Subproject들을 정의해주어야
rootProject.name = 'Project Root Name'
include ':api, ':core', ':batch'

 

 

🤔 build.gradle??

모든 Gradle Build는 한개 이상의 build script를 가지고 있어야한다

build script를 나타내는 파일인 build.gradle 파일은 아래 두가지 타입의 dependency 들을 정의하고 있다

  • Gradle과 Build Script가 빌드시에 의존하는 라이브러리 혹은 플러그인
  • 프로젝트 소스코드가 의존하는 라이브러리

Plugin과 Dependency의 차이는??

👉 Plugin

특정 도메인에 포함된 task들의 집합 형태로 패키지화 되어있음

gradle에 포함되어있지 않은 task들을 plugin을 apply함으로써, task들을 따로 정의하지 않아도됨

task 뿐만 아니라, properties와 메서드들도 프로젝트에 추가

plugins {
    id 'java'
}

 

예를 들어

java 플러그인은

  • main과 test SourceSet을 세팅
  • 프로젝트의 Main/Test 소스 코드들을 컴파일한 후에 Class 파일들과 결과물을 build 폴더를 생성하여 옮기는 Tasks들을 제공

 

다른 예로는 org.springframework.book 플러그인은

  • 실행가능한 jar, war 파일을 패키징
  • Sprint boot 어플리케이션 실행
  • spring-booty-dependencies 플로그인에서 제공하는 종속성 관리 사용
  • task와 기능들을 담고 있다
// api 모듈 build.gradle
plugins {
    id 'org.springframework.boot' version '3.3.5'
}

tasks.named("bootJar") {
    mainClass = 'com.example.ExampleApplication' // Main class가 무엇인지 커스텀할 수 있는 설정도 plugin에서 제공
}

 

프로젝트에서는 api 모듈을 중심으로 하나의 REST API 서버를 띄워야해서

  • Domain과 Application 레이어에 해당하는 core 모듈의 bootJar task는 비활성화하고,
  • Presentaion 레이어에 해당하는 api 모듈의 build.gradle에서 main 메서드가 있는 Application 파일을 바라보도록 설정했다

 

👉 Dependencies

프로젝트에서 사용할 소스코드 및 라이브러리를 정의하면 Gradle에서 빌드시점에 자동으로 필요한 파일들을 다운로드

dependencies {
	implementation('org.springframework.boot:spring-boot-starter-web')
	implementation('org.springframework.boot:spring-boot-starter-data-jpa')
}
  • implementation - 컴파일과 런타임에 사용
  • compileOnly - 컴파일 시에만 필요
  • runtimeOnly - 런타임에만 필요
  • testImplementation - implementation과 동일하나 test에만 사용
  • testCompileOnly - compileOnly와 동일하나 test에만 사용
  • testRuntimeOnly - testRuntimeOnly와 동일하나 test에만 사용

 

🤔 gradle.properties??

Build Script 내에서 사용할 변수들을 정의해놓는 데에 사용된다

  • 프로젝트 속성 (JVM Options, 메모리 설정 등) 정의 -> 빌드 최적화
  • secret들 관리
  • gradle, plugin, dependency 버전 정의
# Plugin versions
springBootVersion=X.XX.XX
springDependencyManagementVersion=X.XX
// Build Script에서 아래와 같이 사용
plugins {
    id 'java'
    id 'org.springframework.boot' version "${springBootVersion}"
}

 

프로젝트에서는 gradle.properties를 사용하여 환경변수 / 버전 관리를 하였고, 

gradle doc에 따르면 Gradle에서 제공하는 Version Catalog를 이용해서 버전 관리도 가능했다

https://docs.gradle.org/current/userguide/dependency_management_basics.html

 

Dependency Management Basics

To add a dependency to your project, specify a dependency in the dependencies block of your build.gradle(.kts) file. The following build.gradle.kts file adds a plugin and two dependencies to the project using the version catalog above: plugins { alias(libs

docs.gradle.org

 

 

다음 포스팅에서는 

gradle build 시에 아래의 task들이 순차적으로 실행되는데

$ ./gradlew build

> Task :app:compileJava
> Task :app:processResources NO-SOURCE
> Task :app:classes
> Task :app:jar
> Task :app:startScripts
> Task :app:distTar
> Task :app:distZip
> Task :app:assemble
> Task :app:compileTestJava
> Task :app:processTestResources NO-SOURCE
> Task :app:testClasses
> Task :app:test
> Task :app:check
> Task :app:build

BUILD SUCCESSFUL in 764ms
7 actionable tasks: 7 executed

동작원리가 궁금해져서 

뜯어보면서 Java Application이 빌드 -> run 되는 과정을 한번 살펴보고자한다