공부방/JAVA

gradle로 빌드한다는 것은 무슨 말이고 gradle wrapper는 무엇일까

EVO. 2023. 8. 27. 17:30

서론

"Gradle 빌드에 권장되는 사용 방법은 Gradle Wrapper를 사용하는 것이다."

처음에 이 문장을 보고 무슨 말인지 전혀 몰랐다. 그때 내가 아는 지식으로는 gradle은 의존성을 받아오는 녀석이며 컴파일 시점과 런타임 시점때 해당 외부 라이브러리들을 꺼내어서 쓴다는 얕은 지식으로만 이해를 했다. 이번 기회에 한번 알아보겠다.

Gradle

빌드란 소스코드를 컴파일, 테스트, 정적 분석 등을 실행하여 실행 가능한 애플리케이션으로 만들어주는 과정 이다

https://www.youtube.com/watch?v=ntOH2bWLWQs&ab_channel=%EC%9A%B0%EC%95%84%ED%95%9C%ED%85%8C%ED%81%AC

이전에 다양한 라이브러리들이 생기고 개발자가 직접 라이브러리들을 다운로드하고 추가해야하는 번거로움이 있었으며, 개발자들 간의 버전관리도 어려우며 다운받은 jar파일의 보안 위험도 있었다

 

이런 문제를 해결하기 위해서 빌드 도구가 생겼다

빌드 도구는 계속해서 늘어나는 라이브러리들을 자동 추가 및 관리하며 프로젝트를 진행하며 라이브러리의 버전을 쉽게 동기화 해준다 

즉 자바소스를 컴파일하고 package해서 deploy 하는 일을 자동화 해주는 것이다. 

 

Gradle은 이 빌드 도구 중 하나이며 Groovy언어 또는 코틀린 언어를 사용한다. 이중 Groovy언어는 JVM상에서 실행되는 스크립트 언어이고 Java와 유사한 문법 구조를 가지며 호환성이 아주 좋다

 

Gradle 장점

1. 프로젝트를 설정 주입 방식(configuration injection)으로 정의  

  • 빌드도구인 Maven의 상속 구조보다 재사용에 용이
  • 프로젝트의 조건을 체크할 수 있어서 프로젝트별로 주입되는 설정을 다르게 할 수 있다

Gradle의 설정 주입 방식은 기본적으로 프로젝트의 구성을 동적으로 결정할 수 있게 한다. 이는 Gradle이 프로젝트의 설정을 '주입'하는 방식으로 이루어진다. 예를들어, 여러 서브 프로젝트들이 있는 상황에서 각각에 대해 공통된 설정을 적용하고 싶다면, 그 공통된 설정을 모든 서브 프로젝트에 주입할 수 있다.

Gradle은 각각의 프로젝트가 독립적으로 조건을 체크할 수 있게 해줘서, 같은 빌드 스크립트라도 서로 다른 조건에 따라 다르게 작동하도록 할 수 있다. 즉, 특정조건에 따라 다른 라이브러리를 사용하도록 하거나 빌드과정을 달리 할 수 있다.

 

해당 부분은 multi project를 진행할 때 진가를 발휘한다

 

2. 멀티 프로젝트 빌드 

하나의 repository에 여러개의 하위 프로젝트를 구성할 경우가 있을텐데 이 하위 프로젝트들은 공통으로 쓰이는 것이 있을 것이다.

 

처음에 프로젝트를 생성하고 settings.gradle을 보면

rootProject.name = '본인이 저장한 프로젝트이름'

임을 확인할 수 있다.

 

우리는 build.gradle에서 멀티프로젝트 빌드를 만들 것이다. 

먼저 admin 과 user 의 모듈  그리고 admin과 user가 공통으로 쓸 core을 만든다

 

 

그리고나서 settings.gradle에서 새로 만들어진 모듈에 대해서 코드를 추가하면 되는데 

rootProject.name = 'javaStudy'
include 'javaStudy-admin'
include 'javaStudy-user'
include 'javaStudy-core'

추가한 모듈들을 settings.gradle에 include를 해줘야 한다. 

그리고 build.gradle에서 이와 같이 하위 프로젝트, 공통 프로젝트들에 대해 해야될 역할을 다르게 부여할 수 있다. 해당 코드는 아래 출처의 블로그에서 사용한거라 정확하지는 않으므로 이렇게 하위모듈 공통모듈에 빌드방식을 다르게 할 수 있다는 것만을 인지했으면 좋겠다 

 

buildscript {
    ext {
        springBootVersion = '3.1.3'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
        classpath "io.spring.gradle:dependency-management-plugin:1.0.11.RELEASE"
    }
}

// 하위 모든 프로젝트 공통 세팅
subprojects {
    apply plugin: 'java'
    apply plugin: 'idea'
    apply plugin: 'org.springframework.boot'
    apply plugin: 'io.spring.dependency-management'

    group 'org.example'
    version '1.0-SNAPSHOT'

    sourceCompatibility = '17'
    targetCompatibility = '17'
    compileJava.options.encoding = 'UTF-8'

    repositories {
        mavenCentral()
    }

    // 하위 모듈에서 공통으로 사용하는 세팅 추가
    dependencies {
        compileOnly 'org.projectlombok:lombok'

        annotationProcessor 'org.projectlombok:lombok'
        annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"

        testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
        testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
    }

    test {
        useJUnitPlatform()
    }
}

project(':javaStudy-core') {
    // 공통 코드

    bootJar { enabled = false } // core 은 bootJar 로 패키징 할 필요 없음
    jar { enabled = true }

    dependencies {
    }
}

project(':javaStudy-admin') {
    bootJar { enabled = true }
    jar { enabled = false }

    dependencies {
        compile project(':javaStudy-core') // 컴파일 시 javaStudy-core project 로딩
        implementation 'org.springframework.boot:spring-boot-starter-web'
    }
}

project(':javaStudy-user') {
    bootJar { enabled = true }
    jar { enabled = false }

    dependencies {
        compile project(':javaStudy-core') // 컴파일 시 javaStudy-core 로딩
    }
}

 

3. 빌드속도가 빠르다 

 

점진적 빌드

  • 빌드속도가 빠른 이유는 빌드 실행중 마지막 호출 이후에 task의 입력,출력 혹은 구현이 변경이 됐는지 확인한다.
  • 최신 상태로 간주하지 않는다면 빌드는 실행되지 않는다. 

https://www.youtube.com/watch?v=ntOH2bWLWQs&ab_channel=%EC%9A%B0%EC%95%84%ED%95%9C%ED%85%8C%ED%81%AC

빌드캐시

두 개 이상의 빌드가 돌아가고, 하나의 빌드에서 사용되는 파일들이 다른 빌드에도 사용된다면 Gradle은 빌드 캐시를 이용해 다시 빌드하지 않아도 되므로 재사용해서 빌드시간이 줄어들게 된다.

 

데몬프로세스

  • 서비스의 요청에 응답하기 위해 오랫동안 살아있는 프로세스
  • Gradle의 데몬프로세스는 메모리 상에 빌드 결과물을 보관
  • 이로인해 한 번 빌드된 프로젝트는 다음 빌드에서 매우 적은 시간만 소요된다

이러한 장점들로 인해 빌드도구인 Maven 보다 두 배이상 최대 100배 이상 빠르다고 한다.

https://gradle.org/maven-vs-gradle/

또한 코틀린 기반으로도 작성가능한 gradle은 사용자에게 익숙함을 더하며 가독성에도 maven에 비해 좋은 것같으니 적극 활용하면 좋을 것 같다.

 

Gradle 사용법

Gradle에서 멀티모듈을 사용하는 방법은 나 역시 경험해보지 못했으니 생략하고 가장 우리가 많이 작성하는 부분인 의존성에 대해서만 소개해 보려고 한다

 

우리가 쓰는 외부라이브러리들(dependencies)에서 

  • Spring 관련 의존성은 컴파일 또는 런타임 모두에 활용
  • Lombok은 컴파일시에만 활용
    =>getter,setter,toString등 자주 쓰이는 코드는 컴파일 시에 만들어진다
  • h2databasems은 런타임시에만 활용
  • Spring-boot-starter-test는 테스트에서만 활용

어느 시점에 해당 라이브러리들을 쓰는 지 우리는 인지하고 있고 인지하고 있어야 한다. 이제 이에 맞게 Gradle 설정을 맞춰나가야 한다.

  •  api : a모듈을 의존하는 b모듈 그리고 b모듈을 의존하는 c모듈이 있을 때 내부의존성을 컴파일과 런타임 모두에 보이는 API의존성을 사용하면 a모듈에서 수정한 부분이 있으면 c모듈까지 컴파일타임에 확인이 가능하기 때문에 3개의 모듈 모두 재빌드가 일어난다. 따라서 이 api는 지양하고 있는 것 같다
  • implementation : 내부의존성을 런타임에서만 보이는 구현의존성은 b모듈까지만 재빌드 될수 있도록 할 수 있다 . 
  • compileOnly : 컴파일에만 사용되는 의존성 정의
  • runtimeOnly : 런타임에만 사용되는 의존성 정의 
  • test + Implementation,CompileOnly,RuntimeOnly: 해당 의존성을 테스트 시에만 사용하도록 정의 

이렇게 적절한 것을 사용해서 빌드 속도를 줄이는 것이 우리의 목표이다. 

이로써 gradle로 빌드한다는게 무슨 말인지 어느정도 이해가 갔다 

 

 

Gradle Wrapper란

gradle 빌드에 권장되는 사용방법은 Gradle Wrapper를 사용하는 것이다. 

즉 Gradle Wrapper는 명시된 gradle 버전을 호출하고 명시된 버전의 gradle이 없을 경우 자동으로 다운로드 및 설치하여 빌드 해주는 스크립트 이다. 

 

Gradle Wrapper를 쓰면 다음과 같은 장점이 있다

  • 특정 버전의 Gradle을 프로젝트와 함께 번들링할 수 있으므로, 모든 개발자와 CI 서버가 동일한 버전의 빌드 도구를 사용하는것을 보장
  • 필요한 경우 쉽게 Gradle 버전을 업그레이드 할 수 있다
  • 복잡한 프로젝트 설정 없이 새로운 개발자나 CI 서버가 빠르게 작업 시작이 가능 
  • 환경에 종속되지 않고 프로젝트를 빌드할 수 있다 
    gradle build를 사용하면 로컬에 설치된 gradle과 java를 기준으로 build하지만, ./gradlew build를 실행하면 build.gradle파일에 정의한 내용을 기준으로 build되기 때문에 로컬 환경과 관계없이 프로젝트를 빌드할 수 있다. 
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

gradle-wrapper.properties를 보면 위와 같은 코드를 볼 수가 있는데 distributionUrl에 지정되어 있는 gradle버전을 사용하여 빌드를 하게 된다. 

 

글쓴이 능력이 부족한 탓에 추가적인 내용은 멀티모듈 프로젝트를 직접 구축하고 빌드를 해보면서 공부를 하고 정리해야겠다

 

 

레퍼런스:

 

 

[Spring] 멀티 모듈 프로젝트 만들기

멀티 모듈에 대한 설명 및 프로젝트 만들기

velog.io

 

 

멀티 모듈 적용하기 with Gradle

이번 글에서는 프로젝트를 구성하는 데 있어 멀티 모듈 활용했을 때의 장점과 간단한 설정 방법을 알아본다. 멀티 모듈의 개념을 처음 접하는 사람들이 읽어보기를 추천한다.

tecoble.techcourse.co.kr

https://www.youtube.com/watch?v=ntOH2bWLWQs&ab_channel=%EC%9A%B0%EC%95%84%ED%95%9C%ED%85%8C%ED%81%AC

 

 

 

지속 성장 가능한 소프트웨어를 만들어가는 방법

스프링은 국내에서 정말 많이 쓰이고 있습니다, 개인적으로 많은 회사를 다녀보며 주니어/시니어를 막론하고 많은 분들이 스프링에 함몰되어 개발을 하고 있다는 느낌을 받을 때가 많았고 이

geminikim.medium.com

https://gradle.org/maven-vs-gradle/

 

Gradle | Gradle vs Maven Comparison

High-level performance and feature comparison between Gradle and Maven

gradle.org

 

 

[Gradle] Gradle task 이해와 Gradle Wrapper 사용하기 - SW Developer

1. Gradle Wrapper란? Gradle 빌드에 권장되는 사용 방법은 Gradle Wrapper를 사용하는 것이다. Gradle에는 Wrapper라고 하는 운영체제에 맞춰서 Gradle Build를 수행하도록 하는 배치 스크립트가 있다. 즉, Gradle Wra

wonyong-jang.github.io

 

Spring Boot Gradle Plugin Reference Guide

To manage dependencies in your Spring Boot application, you can either apply the io.spring.dependency-management plugin or use Gradle’s native bom support. The primary benefit of the former is that it offers property-based customization of managed versio

docs.spring.io