거북이-https://velog.io/@violet_evgadn 이전완료

build.gradle 사용법 본문

웹 개발/Spring(활용)

build.gradle 사용법

VioletEvgadn 2022. 11. 27. 13:54

repositories

Project에 활용할 외부 Library를 저장하고 있는 저장소에 대한 설정을 담당한다.

처음 Gradle Project를 생성하면 "mavenCentral()"이 기본적으로 설정되어 있을 것이다.

 

Maven Central이나 JCenter 같은 공공 Repository 뿐만이 아니라 사내 Maven Repository에서 Library를 가져올 수도 있다.

공공 Repository가 아닌 Private Repository를 활용하기 위한 방법은 아래와 같다.

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

만약 allowInsecureProtocol(true)가 없다면 Build에 실패할 것이다.

이는 최신 Gradle에서 보안을 위해 http 서버를 사용하는 것을 허용하고 있지 않기 때문이다.

 

따라서 "allowInsecureProtocol(true)" 문구를 통해 강제로 http 서버도 사용을 허락하여 SSL이 설치된 https가 아닌 일반 http에서도 Repository를 활용 가능하게 하는 것이다.


ext

인자를 buildScript(build.gradle) 전역에서 활용하기 위한 전역 변수 설정을 위해 사용된다.

 

ext에서 지정한 전역 변수는 ${변수 이름}으로 사용할 수 있다.

얼마나 많이 사용하겠냐 싶겠지만 버전 관리를 쉽게 할 수 있다는 점에서 꽤나 많이 활용하는 문법이다.

 

아래 queryDSL 예시를 통해 사용 방법을 이해해보자.

ext {
    queryDslVersion = "5.0.0"
}

....
dependencies {
    implementation "com.querydsl:querydsl-jpa:${queryDslVersion}"
    implementation "com.querydsl:querydsl-apt:${queryDslVersion}"
    implementation "com.querydsl:querydsl-core:${queryDslVersion}"
}

plugins

plugins를 통해 사용할 Gradle Plugin을 명시할 수 있다.

plugins를 이해하기 위해선 먼저 Gradle Plugin에 대해 이해할 필요가 있을 것이다.

 

Gradle은 "Task"라는 작업 단위로 이루어져 있다. 그리고 Task라는 작업 단위가 모두 실행되면 build.gradle 같은 Script에 지정한 대로 Build 과정이 이루어지게 되는 것이다.

 

그리고 Task들을 1개 Group으로 묶어 1개의 빌드 과정을 만들 수도 있다.

 

예를 들어 전체 Build 과정이 A, B, C라는 단계로 크게 나눌 수 있다고 가정하자. 그런데 A, B, C 단계는 각각 여러 개의 Task로 이루어져 있을 것이다. 이때 A, B, C라는 큰 빌드 단계를 "Gradle Plugin"이라고 하는 것이다.

 

plugins 부분에 Gradle Plugin을 지정해줌으로써 해당 기능을 사용하기 위해 필요한 모든 Task를 일일이 입력할 필요 없이 오직 1줄로만 여러 Task를 처리할 수 있게 되는 것이다.

 

사용 방법은 아래와 같다.

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를 구성한 이후 작성한 Build Script를 통해 모든 Task를 거쳐 빌드 과정을 수행하는 Tool이라고 말할 수 있다.

 

아무래도 Task가 Gradle의 기본 단위이다 보니 Task에서 활용할 수 있는 수많은 기능들이 있는데, 여기에선 알아두면 좋은 것들 몇 개만 소개하도록 하겠다.

 

◎ 기본 사용 방법

먼저 build.gradle에 task는 아래와 같이 선언할 수 있다.

task sayHello {
    println 'Hello'
}

 

이렇게 입력한 Task는 왼쪽에 초록색 재생버튼을 클릭함으로써 실행할 수 있다.(IntelliJ 기준)

또한 Termianl 창에서 "gradle [task 이름]" 형태로 실행시킬 수도 있다.

(참고로 필자는 Local 환경에 Gradle을 설치하지 않았으므로 gradlew를 통해 명령어를 실행하겠다. 이 말이 이해가 안 된다면 이전 블로그 글로 정리했던 "Gradle Wrapper"에 대해 다시 읽어보고 오자.)

"Configure project"로 시작해 "Hello" 문구가 출력됨을 볼 수 있다.

 

◎ doFirst, doLast

doFirst는 Task의 가장 처음, doLast는 Task의 가장 마지막에 메서드를 실행할 수 있게 하는 예약어이다.

위 문장과 같이 설명을 하고 있는 몇 개 사이트를 보았다. 하지만 개인적으로는 doFirst는 doLast보다 먼저 처리해야 할 Block이라고 설명하는 것이 맞는 것 같다.

 

위에서 볼 수 있듯 task 안의 명령은 "Configure project"의 Output으로 나오게 된다.

하지만 doFirst와 doLast는 "Task :[Task 이름]"의 Ouput으로 출력된다.

 

즉, doFirst는 "doLast보다 먼저 수행되는 Task Block", doLast는 "doFrist보다 나중에 수행되는 Task Block"으로 설명하는 것이 더 맞지 않나 생각한다.

 

doFirst와 doLast는 아래와 같이 사용할 수 있다.

task hello {
	doFirst {
		println 'hello'
	}

	doLast {
		println 'bye'
	}
}

 

 

◎ Parameter 전달

Gradle에서는 -P[파라미터 이름]을 통해 Parameter 값을 전달할 수 있다.

여기서 Parameter 이름은 "def" 등으로 지정하지 않아도 바로 전달해 줄 수 있다.

 

말로만 하면 조금 복잡한 개념이기 때문에 예시를 하나 들어보자.

task calc {
	def x_i = x.toInteger();
	def y_i = y.toInteger();

	println x_i + " + " + y_i +" = " + (x_i + y_i);
}

보면 def로 x_i, y_i로 선언했다. 하지만 -P를 통해 파라미터 전달을 할 때는 "x", "y"로 값을 전달해줘야 한다.

 

즉, 위 Task에 정상적으로 operation, x_i, y_i 값을 설정하기 위해선 아래와 같이 입력해야 하는 것이다.

./gradlew calc -Px=2 -Py=10

정상적으로 x_i = 2, y_i = 10으로 처리되었음을 볼 수 있다.

 

◎ dependsOn

만약 특정 Task가 다른 Task에 종속성을 가진다면 어떻게 해야 할까?

"dependsOn" 문구를 통해 실행시킬 Task에 종속성이 있어 무조건 선행되어야 하는 Task를 미리 지정할 수 있다.

 

예시를 들어보자. "bye"라는 Task를 수행하기 이전 "hello" Task와 "introduce" Task가 선행되어야 하는 상황을 가정하자.

task bye(dependsOn:['hello', 'introduce'])  {
	doLast {
		println "bye"
	}
}

task hello {
	doLast() {
		println "hello"
	}
}

task introduce {
	doLast() {
		println "my name is DJLim"
	}
}

"bye"만 실행시켰지만 dependsOn에 선언했던 "hello", "introduce" Task도 실행되었음을 알 수 있다.

참고로 실행하는 순서는 dependsOn에 선언했던 Task 명 순서이다.


Gradle Dependency

◎ api

compile과 동일한 동작을 수행하는데, Gradle에서는 compile보다는 api 사용을 권장한다.

 

api은 Project에 의해 노출된 API가 사용하는 Production Source까지 컴파일하는데 필요한 종속성을 의미한다.

 

◎ implementation

Production Source만을 컴파일하여 외부에 전달하는 종속성을 의미한다.

 

◎ 예시로 확인하는 api vs implementation

말로만 들으면 매우 어려운 것 같다. 이는 예시를 통해 배우는 것이 훨씬 효율적이다.

내가 A Project를 Compile 하여 배포한다고 가정하자. 그런데 A Project는 (B, C, D) Library를 활용하고 있다.

이때 내가 Compile했던 A Project를 다른 사람이 사용한다고 가정해보자.

 

이때 API로 설정했다면 A Project를 활용하는 사람은 B, C, D Library가 활용되었음을 파악할 수 있다. 하지만 implementation을 활용했다면 A Project를 활용하는 사람은 (B, C, D) Libary가 활용되었는지 아닌지 알 수가 없게 되는 것이다.

출처 : https://velog.io/@csk917work/gradle-theory#plugin-vs-dependencey

위 사진을 통해 보면, Modified A 입장에서 "api(compile)"의 경우 C가 활용되었다는 것까지 파악할 수 있으며 Compile을 수행할 때 C 또한 Rebuild, 즉 빌드 과정을 거쳐야 한다.

하지만 implementation의 경우 B가 활용되었다는 것만 알 뿐 B에서 C가 활용되었다는 것까지는 알지 못한다. 따라서 B만을 Rebuild 하게 된다. 이 때문에 B만 Rebuild 하는 implementation의 Build 속도가 더욱 빠른 것이다.


dependencies

의존성 라이브러리를 추가할 때 사용하는 Part로 아마 가장 많이 활용하는 분야일 것이다.

제공하는 대표적인 옵션은 아래와 같다.

  • implementation : 의존 Library 수정 시 수정했던 모듈까지만 재 빌드
  • api : 의존 Library 수정 시 수정했던 모듈과 수정한 모듈을 의존하는 모듈들 모두를 전부 재 빌드
  • compileOnly : compile 시에만 빌드하고 빌드 결과물에는 포함하지 않음
  • testImplementation : 테스트 코드를 수행할 때만 적용
  • annotationProcessor : Compile 단계에서 Annotation에 정의된 일렬의 프로세스를 동작하게 하는 것

 

annotationProcessor가 좀 특이한데, 사실 Annotation Processor는 "의존성 주입"이라고 하기에는 애매하다.

Annotation Processor란 Annotation을 사용했을 때 Compile 단계에서 Annotation이 가지고 있는 의미를 선언된 객체에 부여해주는 것을 말한다.

그리고 annotationProcessor란 "이 라이브러리가 Annotation으로 활용되므로 Compile 단계에서 Annotation 의미를 부여해야 한다"라는 것을 알리는 옵션인 것이다.

 

대표적으로 annotationProcessor를 활용하는 Library가 "Lombok"이다. Lombok은 알다시피 @Getter, @Setter, @Data 등 모든 Library 내의 기능을 어노테이션으로 활용한다.

따라서 Gradle 측에 Compile 할 때 Annotation 의미를 부여해줘야 한다고 알리는 것이다.

(annotationPorcessor는 꼭 기입하지 않아도 정상 작동하는 경우도 있지만, 선언을 추천하기 때문에 웬만하면 선언해주도록 하자)

 

 

'웹 개발 > Spring(활용)' 카테고리의 다른 글

Spring Web 메인 클래스  (0) 2022.08.05
AOP 실습  (0) 2022.08.04
DI 주입 실습  (0) 2022.08.04
스프링 빈 활용  (0) 2022.08.03
Comments