팀프로젝트로 만든 뉴스 크롤링 어플을 정리하면서 대충 넘겼던 부분을 다시 공부하기 시작했는데 처음부터 막혔다. server측과 fastapi측 구현을 따로해서 각각 서버를 배포했었는데 기존에 사용했던 render가 서버를 재배포하는데 시간도 오래걸리고 15분이상 사용하지 않으면 sleep상태에 접어들어서 실질적인 배포라 할 수 없던 상황이었다. 시간이 없어서 대충 gpt랑 싸워가면서 코드를 작성했는데 너무 정리가 안 되있어서 한 번 정리를 해보려고 한다.
Gradle이란 무엇인가
✅ Gradle이란 JAVA/Kotlin등 JVM 기반 프로젝트 전반을 위한 오픈 소스 빌드 자동화 도구로 Groovy 혹은 Kotlin DSL을 이용해 Task(무엇을 할 것인지) 와 Dependencies(어떤 의존성이 필요한지)를 선언한다.
아래는 Groovy와 Kotlin DSL의 차이점을 표로 나타낸 것이다.
| 언어 | Groovy (동적 타입) | Kotlin (정적 타입) |
| 파일 확장자 | .gradle | .gradle.kts |
| IDE 자동완성 | 낮음 (IntelliJ나 Android Studio에서 제한적) | 높음 (Kotlin 언어의 정적 타입 덕분에 IntelliJ에서 강력한 자동완성 지원) |
| 문법 안정성 | 낮음 (런타임 오류 가능성 있음) | 높음 (컴파일 타임에 오류 잡힘) |
| 학습 난이도 | 쉬움 (Groovy는 자바와 비슷함) | 약간 높음 (Kotlin을 알아야 함) |
| 대표 사용 예시 | 기존 프로젝트 대부분, Android에서 기본 사용 | 최신 Kotlin 기반 프로젝트, Gradle 공식 권장 방식 중 하나 |
*DSL : Domain-Specific Language(도메인 특화 언어)의 약자로 특정 목적이나 분야에 맞게 설계된 언어이다.
- 정적 타입 언어(Static Typing)란 컴파일 할 때 변수의 타입이 결정되는 언어로 타입 오류가 컴파일 시점에 잡힌다. ex) Java, Kotlin, C, C++
int number = 10; // number는 항상 int 타입
number = "Hello"; // ❌ 컴파일 오류 (문자열을 int에 대입 불가)
실수로 다른 타입을 넣는 버그를 컴파일 시점에 방지할 수 있고 IDE 자동완성&리팩토링이 강력하다. 또한 JVM,컴파일러가 타입을 알고있어서 성능 최적화가 쉽다. 반면, 타입 선언으로 코드가 길고 엄격해질 수 있으며 간단한 스크립트에는 귀찮을 수 있다.
- 동적 타입 언어(Dynamic Typing)란 실행할 때 변수의 타입이 결정되기 때문에 타입 오류가 런타임 시점에 발생한다. ex) Python, JavaScript, Groovy
x = 10 # x는 int
x = "Hi" # x는 이제 str (가능)
코드가 간결하고 빠르게 작성 가능하지만 런타임 에러 발생 가능성이 증가하고 IDE 자동완성/리팩토링이 제한적이기 때문에 큰 프로젝트에서는 유지 보수가 어려울 수 있다.
즉, Groovy와 Kotlin DSL이라는 스크립트 언어가 Gradle에서 프로젝트 빌드, 의존성 관리, 플러그인 설정에 사용된다.
Gradle 구성 요소
1. Settings 파일 ( settings.gradle[.kts] )
- 멀티 프로젝트에서 포함할 하위 모듈을 정의한다.
rootProject.name = 'newsnap'
include 'server', 'fastapi-adapter'
2. 빌드 스크립트 ( build.gradle[.kts] )
- 플러그인, 의존성, 리포지토리, 태스크를 선언한다.
plugins {
id 'java'
id 'org.springframework.boot' version '3.1.4'
}
group = 'com.example'
version = '0.1.0'
sourceCompatibility = '17'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
}
tasks.register("hello") {
doLast {
println("Hello, Gradle!")
}
}
2-1 Gradle에서 plugin이란 빌드 스크립트에 새로운 기능, 태스크, 설정을 추가해주는 모듈이다.
대표적인 플러그인 예시는 다음과 같다.
| java | Java 컴파일, JAR 생성 등의 기본 기능 추가 |
| org.springframework.boot | Spring Boot 빌드, 실행, bootJar 기능 제공 |
| io.spring.dependency-management | Spring 의존성 버전 자동 관리 |
| application | 자바 애플리케이션 실행을 위한 mainClass 설정 등 |
| kotlin("jvm") | Kotlin 코드 빌드 및 설정 추가 (Kotlin DSL용) |
대부분은 Gradle Plugin Portal에 등록되어 있지만 일부는 Spring처럼 별도 저장소에서 제공한다. ex) maven { url "https://repo.spring.io/plugins-release" }
2-2 Gradle에서 dependencies란 프로젝트가 빌드되고 실행되기 위해 필요한 라이브러리 목록이다.
예를 들어 Spring Boot를 사용하기 위해 필요한 spring-boot-starter-web 같은 라이브러리를 dependencies{}블록 안에 명시하면 자동으로 다운로드하고 빌드 시 포함해준다.
선언 방식(Configuration) 은 다음과 같다.
| implementation | 일반적으로 가장 많이 쓰이는 실행 및 컴파일용 라이브러리 |
| api | (라이브러리 모듈용) 공개 API로 외부에 노출되는 의존성 |
| compileOnly | 컴파일에만 필요, 실행 시에는 제외 (ex: Lombok) |
| runtimeOnly | 실행 시에만 필요, 컴파일에는 불필요 (ex: JDBC 드라이버) |
| testImplementation | 테스트 코드에서만 필요한 의존성 (ex: JUnit) |
| annotationProcessor | 어노테이션 프로세서용 (ex: Lombok) |
2-3 Gradle에서 repositories란 필요한 라이브러리(dependencies)를 어디서 다운로드 할 지 지정하는 위치이다.
의존성을 dependencies 블록에 적어도 어디서 받아야 할지를 모르면 빌드가 실패한다.
대표적인 repository 종류는 다음과 같다.
| Maven Central | mavenCentral() | 가장 널리 사용되는 공개 저장소 |
| JCenter (중단됨) | jcenter() | 예전에는 인기 있었지만 이제는 중단됨 ❌ |
| google() | Android 라이브러리 전용 | |
| Spring | maven { url = "https://repo.spring.io/milestone" } | Spring Boot의 마일스톤/스냅샷 버전 제공 |
| 로컬 저장소 | mavenLocal() | 내 PC에 직접 설치된 라이브러리 검색용 |
만약 사내 전용 라이브러리를 사용할 땐 사설 Nexus 저장소 등을 추가 가능하다.
3. Gradle Wrapper (gradlew , gradlew.bat , gradle/wrapper/.. )
- Gradle을 설치하지 않아도 프로젝트를 빌드할 수 있게 해주는 도구로 Wrapper를 사용하면 Gradle이 없어도 자동으로 다운로드 되고 프로젝트마다 Gradle 버전이 통일된다.
gradle wrapper 명령어로 실행되고 다음과 같은 파일들이 생긴다.
| gradlew | 유닉스/맥용 실행 스크립트 (./gradlew build) |
| gradlew.bat | 윈도우용 실행 스크립트 (gradlew.bat build) |
| gradle/wrapper/gradle-wrapper.properties | 사용될 Gradle 버전과 다운로드 URL 설정 |
| gradle/wrapper/gradle-wrapper.jar | Wrapper 로직이 들어 있는 실행용 JAR 파일 |
다른 빌드 도구와의 차이점
지금까지 계속 빌드라는 말을 썼지만 정확히 빌드가 무엇을 뜻하는지 와닿지 않아서 한 번 정리가 필요할 것 같다.
✅ 빌드는 개발자가 작성한 소스코드를 실행 가능한 형태로 만드는 모든 과정을 뜻한다.
| 단계 | 설명 | 예시 |
| 1. 컴파일 | 소스코드를 기계어로 바꿈 | .java → .class, .kt → .class |
| 2. 의존성 처리 | 필요한 외부 라이브러리 다운로드 & 포함 | spring-boot-starter-web, jjwt |
| 3. 리소스 처리 | 이미지, 설정 파일, 정적 파일 포함 | application.yml, .html, .json 등 |
| 4. 패키징 | 하나의 실행파일(JAR, APK 등)로 압축 | build/libs/app.jar 생성 |
| 5. 테스트 | 단위 테스트 자동 실행 | ./gradlew test |
| 6. 배포 파일 생성 | 실제 서비스에 올릴 실행 파일 완성 | bootJar, assemble 등 |
| Gradle | Maven | Ant | |
| DSL | Groovy/Kotlin 기반 선언형 | XML 기반 선언형 | XML + 스크립트형 |
| 성능 | 데몬, 캐시, 병렬 → 빠름 | 중간 | 느림 |
| 확장성 | 플러그인·커스텀 태스크 자유로움 | 플러그인 많으나 설정 제한적 | 스크립트 자유도 높으나 복잡 |
| 멀티모듈 지원 | 기본 | 기본 | ANT-Contrib 필요 |
Gradle 프로젝트 만들기
지금까지 Gradle로 빌드를 생성하려면 Setting 파일 (settings.gradle) , 빌드 스크립트 (build.gradle) , wrapper (gradlew, gradlew.bat, gradle/wrapper/*)가 필요함을 알 수 있었다.
Spring boot프로젝트를 빌드하기 전에 Spring boot에 대한 개념을 먼저 잡고 가야겠다.
✅ Spring이란 자바 기반으로 웹/서버/애플리케이션을 쉽게 만들 수 있도록 도와주는 프레임워크이다.
Spring의 핵심 개념은 다음과 같다.
개념 이름 (약자) 설명 예시 코드 목적/효과
| DI | Dependency Injection (의존성 주입) | 필요한 객체를 직접 만들지 않고 외부에서 주입받음 | @Autowired UserService | 결합도 ↓, 테스트 쉬움 |
| IoC | Inversion of Control (제어의 역전) | 객체 생성/관리를 개발자가 아닌 Spring이 담당 | @Component, @Service | 객체 생명주기 자동 관리 |
| AOP | Aspect-Oriented Programming (관점 지향 프로그래밍) | 공통 관심 기능(로깅, 보안 등)을 핵심 로직에서 분리 | @Aspect, @Before(...) | 코드 중복 ↓, 관심사 분리 |
| MVC | Model-View-Controller (웹 계층 구조) | 웹 요청을 컨트롤러-서비스-DB로 분리 처리 | @RestController → @Service → @Repository | 유지보수성 ↑, 협업 쉬움 |
또한 주요 모듈은 다음과 같다.
| Spring Core | DI/IOC 기능 제공 |
| Spring Web (MVC) | 웹 애플리케이션 구조 제공 |
| Spring JDBC / JPA | 데이터베이스 연동 |
| Spring Security | 로그인/권한 등 보안 처리 |
| Spring AOP | 로그, 트랜잭션 분리 |
| Spring Test | 테스트 지원 기능 |
Spring Boot는 이러한 Spring을 쉽게 쓰기 위한 도구이다.
그럼 본론으로 넘어가서 Spring Initializer는 https://start.spring.io 에서 제공되는 Spring Boot 프로젝트 생성기로 필요한 의존성과 설정을 선택하면 자동으로 Gradle 혹은 Maven 기반의 Spring Boot 프로젝트를 생성해준다.
Spring Initializer로 생성되는 전체 기본 구조는 다음과 같다.
demo/
├── build.gradle.kts ← ✅ Gradle 빌드 스크립트 (Kotlin DSL일 때)
├── settings.gradle.kts ← ✅ 프로젝트 이름 및 설정
├── gradlew ← ✅ Gradle Wrapper 실행 파일 (Linux/macOS)
├── gradlew.bat ← ✅ Gradle Wrapper 실행 파일 (Windows)
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar ← ✅ Gradle 실행 로직
│ └── gradle-wrapper.properties ← ✅ 사용될 Gradle 버전 정보
├── .gitignore ← ✅ Git에 올릴 필요 없는 파일 목록
├── HELP.md ← ℹ️ Spring Initializr에서 자동 생성된 도움말
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/example/demo/
│ │ │ └── DemoApplication.java ← ✅ 메인 클래스 (@SpringBootApplication)
│ │ └── resources/
│ │ ├── application.properties ← ✅ 설정 파일 (기본 비어 있음)
│ │ ├── static/ ← (웹 정적 파일용 폴더, 비어 있음)
│ │ ├── templates/ ← (타임리프 같은 템플릿용 폴더, 비어 있음)
│ │ └── application.yml ← ❌ (선택사항, 기본은 .properties)
│
│ └── test/
│ └── java/
│ └── com/example/demo/
│ └── DemoApplicationTests.java ← ✅ 기본 테스트 클래스
만약 Gradle + Java 로 생성한 경우 Gradle에 필요한 build.gradle, settings.gradle, gradlew, gradlew.bat, gradle/wrapper 뿐만아니라 .gitignore, HELP.md 디렉토리 구조(src/main/java, src/test/java) 등이 자동으로 생성된다.

