Server/Gradle

Gradle이란 무엇인가? (+ Ant, Maven 비교)

JaeHoney 2022. 5. 28. 19:12

Gradle이란

그래들(Gradle)은 그루비(Groovy)를 기반으로 한 빌드 도구이다. Ant, Maven과 같은 이전 세대 빌드 도구의 단점을 보완하고 장점을 취합하여 만든 오픈소스로 공개된 빌드 자동화 도구이다.

 

빌드 자동화의 목적은 소프트웨어 개발자가 반복적으로 해야 하는 코딩을 잘 짜여진 프로세스를 통해 자동으로 실행하며, 믿을 수 있는 결과물을 생산해내는 일련의 과정을 말한다.

 

짧게 요약하면 라이브러리를 간편하게 추가하고 관리할 수 있고, 버전도 효율적으로 동기화해서 개발자가 비즈니스 로직에 집중할 수 있게 도와준다.

 

빌드 도구는 Ant -> Maven -> Gradle 순으로 발전되어 왔다.

이전 세대 빌드 도구의 특징

앞서 언급했듯 이전 세대 빌드 도구는 대표적으로 Ant, Maven이 있다. 아래의 특징을 살펴보자.

 

[Ant]

  • XML 기반으로 빌드 스크립트를 작성한다.
  • 자유롭게 빌드 단위를 지정할 수 있다.
  • 쉽고 간단하다.
  • 프로젝트가 커지면 스크립트 관리나 빌드 과정이 복잡하다.
  • 생명주기(Lifecycle)을 갖지 않아서 각각의 target에 대한 의존 관계를 명시해야 한다.

[Maven]

  • XML 기반으로 작성한다.
  • 생명주기(Lifecycle)와 프로젝트 객체 모델(POM, Project Object Model)이란 개념이 도입됐다.
  • Ant의 장황한 빌드 스크립트를 개선했다.
  • pom.xml에 필요한 라이브러리를 선언하면 자동으로 해당 프로젝트로 불러온다.
  • 학습 장벽이 높다.
  • 라이브러리가 서로 의존하는 경우 복잡해질 수 있다.

Gradle의 특징

Gradle은 앞서 언급한 Ant와 Maven이 가진 장점을 함께 가지고 있다. 의존성 관리를 위한 다양한 기능을 제공하고 빌드 스크립트를 XML 언어가 아닌 JVM에서 동작하는 스크립트 언어 그루비 기반의 DSL(Domain Specific Language)를 사용한다.

 

그루비(Groovy)는 자바 문법과 유사해서 자바 개발자가 쉽게 익힐 수 있는 장점이 있으며 Gradle Wrapper를 이용하면 Gradle이 설치되지 않은 시스템에서도 프로젝트를 빌드할 수 있다.

 

추가적으로 메이븐(Maven)의 pom.xml을 Gradle 용으로 변환할 수도 있으며 Maven의 중앙 저장소도 지원하기 때문에 라이브러리를 모두 그대로 가져다 사용할 수 있다.

 

Gradle이 Maven보다 좋은 점을 정리하면 다음과 같다.

 

[Maven]

  • Maven의 경우 Build를 XML로 정의하기에는 어려운 부분이 많다.
    • 설정이 길어지고 가독성이 떨어진다.
    • 의존 관계가 복잡할 경우 풀어내기가 어렵다.

[Gradle]

  • Gradle에서는 그루비 기반의 DSL을 사용한다.
    • 의존 관계가 복잡하더라도 가독성 좋게 풀어낼 수 있다.
    • 동적인 Build를 Groovy 스크립트로 플러그인을 호출하거나 직접 코드를 짜면 된다. (Java와 문법이 유사하다.)
  • Gradle 설치 없이 Gradle Wrapper를 이용해서 빌드를 지원한다.
  • 상속 구조를 활용해서 멀티 모듈을 구현할 수 있다.
  • 빌드 속도가 Maven보다 10~100배 빠르다고 한다.
  • 기존의 빌드 스크립트를(ant, maven)을 간단하게 변환할 수 있다.

Gradle 설치

MacOS 기준으로 간단하게 brew를 이용하면 간편하다. 주의할 것은 설치된 JDK 또는 JRE 버전이 8 이상이어야 한다.

$ brew install gradle
 

build.gradle

build.gradle 파일은 빌드 스크립트라고  부르며, 정확하게는 빌드 구성 스크립트(Build Configuration Script)라고 한다.

 

빌드 구성 스크립트는 의존성이나 플러그인 설정 등과 같은 빌드에 필요한 설정을 하게 된다.

 

build.gradle을 구성하는 요소와 다양한 기법에 대해 알아보자.

repositories 메소드

repositories 메소드는 저장소 설정을 담당한다. 클로저 내용은 RepositoryHandler를 통해 실행된다. RepositoryHandler는 메이븐 중앙 저장소 추가를 위한 mavenCentral 메소드와 Bintray의 jCenter 저장소 추가를 위한 jcenter 메소드를 제공한다.

 

예를 들어 사내 maven repository에서 라이브러리를 가져올 때 아래와 같이 명시한다.

repositories {
    mavenCentral()
    maven {
        allowInsecureProtocol(true)
        url 'https://repo.company.com/repository/maven-repository/'
    }
}

ext 메소드

ext 메소드는 그 인자를 buildScript 에서 전역변수로 사용하기 위해 사용된다. 

ext {
    queryDslVersion = '4.4.0'
}

dependencies 메소드

의존성 라이브러리를 추가할 때 사용한다. 가장 많이 봤을 것이다.

 

대표적으로 아래의 옵션들을 제공한다.

  • implementation
    • 의존 라이브러리 수정시 본 모듈까지만 재빌드한다.
  • api
    • 의존 라이브러리 수정시 본 모듈을 의존하는 모듈들을 전부 재빌드한다.
  • compileOnly
    • compile 시에만 빌드하고 빌드 결과물에는 포함하지 않는다.
  • testImplementation
    • 테스트 코드를 수행할 때만 적용
  • annotationProcessor
    • annotation processor 명시 (ex. annotationProcessor 'org.projectlombok:lombok')

플러그인 추가

plugins는 Gradle 플러그인을 사용하기 위한 것이다.

 

plugin을 등록하면 해당 플러그인에 포함된 수많은 Task들이 Gradle 파일로 들어온다.

plugins {
    id 'org.springframework.boot' version '2.5.1'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
    id "org.asciidoctor.convert" version "1.5.9.2"
    id 'java'
}

Task

Gradle의 실행 작업 단위가 태스크(task)이다. Gradle은 기본적으로 태스크를 수행하며 태스크를 구성하고 작성하는 것이 빌드 스크립트를 작성하는 과정이다.

 

task는 아래와 같은 구조를 작성하면 된다.

task 태스크이름 {
    ... 작업들
}

 

문자열을 출력하는 간단한 태스크를 작성해보자. build.gradle 파일에 아래와 같이 작성해주면 된다.

task sayHello {
    println 'Hello'
}

실행은 터미널에서 gradle task으로 형태로 입력하면 된다.

gradle sayHello

IntelliJ를 비롯한 IDE를 사용하고 있으면 build.gradle에서 해당 태스크 위치의 버튼으로 실행할 수도 있다.

doFirst, doLast

doFirst를 사용하면 해당 구문을 태스크에서 가장 처음 수행할 수 있다. doLast는 가장 마지막에 수행할 구문을 정의할 수 있다.

task hello {
    doFirst {
        println 'hello'
    }

    doLast {
        println 'bye'
    }
}

[Result]

> Task :hello
hello
bye
BUILD SUCCESSFUL in 598ms
1 actionable task: 1 executed

-q task

태스크를 실행할 때 -P파라미터이름=값을 이용하여 파라미터를 전달할 수 있다.

task hello {
    def variable = count.toInteger()
    println('hello ' + variable)
}

 

[Result]

$ gradle -q hello -Pcount=3
hello 3

dependsOn

태스크가 실행될 때 의존성을 지정하여 태스크의 실행 순서를 지정할 수 있다. dependsOn를 사용하여 먼저 실행할 태스크를 지정할 수 있다.

task hello(dependsOn:['aaa', 'bbb'])  {
    doFirst {
        println("*** start:hello task ***")
    }
    doLast {
        println("*** end:hello task ***")
    }
}
 
task aaa {
    doLast {
        println("<< This is A task! >>")
    }
}
 
task bbb {
    doLast {
        println("<< I'm task B!! >>")
    }
}

[Result]

$ gradle hello

> Task :aaa
<< This is A task! >>

> Task :bbb
<< I'm task B!! >>

> Task :hello
*** start:hello task ***
*** end:hello task ***

 


Reference