본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 12. 20. · 5 Views
스프링 부트 3 시작하기 완벽 가이드
초급 개발자를 위한 스프링 부트 3 입문서입니다. 프로젝트 생성부터 설정, 새로운 기능까지 실무에 필요한 핵심 개념을 쉽고 재미있게 배워봅니다.
목차
1. 스프링 부트란
신입 개발자 김개발 씨가 첫 프로젝트 회의에 참석했습니다. 팀장님이 말씀하셨습니다.
"이번 프로젝트는 스프링 부트로 진행합니다." 김개발 씨는 고개를 끄덕였지만 속으로는 궁금했습니다. 스프링 부트가 정확히 뭘까요?
스프링 부트는 스프링 프레임워크를 더 쉽게 사용할 수 있도록 만든 도구입니다. 마치 자동차를 운전할 때 자동 변속기를 사용하는 것처럼, 복잡한 설정을 자동으로 처리해줍니다.
이를 통해 개발자는 비즈니스 로직 작성에만 집중할 수 있습니다.
다음 코드를 살펴봅시다.
// 스프링 부트 애플리케이션의 시작점
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
// 단 한 줄로 애플리케이션 실행
SpringApplication.run(MyApplication.class, args);
}
}
// 간단한 REST API 컨트롤러
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello, Spring Boot!";
}
}
김개발 씨는 점심시간에 선배 개발자 박시니어 씨를 찾아갔습니다. "선배님, 스프링 부트가 정확히 뭔가요?
그냥 스프링이랑 뭐가 다른 건가요?" 박시니어 씨가 웃으며 대답했습니다. "좋은 질문이네요.
스프링 부트를 이해하려면 먼저 스프링의 역사를 알아야 해요." 스프링의 역사와 문제점 스프링 프레임워크는 2004년에 등장한 자바 개발의 혁명이었습니다. 하지만 문제가 있었습니다.
설정이 너무 복잡했던 것입니다. 예를 들어 간단한 웹 애플리케이션을 만들려면 XML 설정 파일을 수십 개 작성해야 했습니다.
데이터베이스를 연결하려면 DataSource를 설정하고, TransactionManager를 설정하고, EntityManagerFactory를 설정하는 등 끝없는 설정의 연속이었습니다. 초보 개발자들은 실제 비즈니스 로직을 작성하기도 전에 설정 파일과 씨름하다가 지쳐버렸습니다.
"왜 이렇게 복잡한 거죠?"라는 질문이 끊이지 않았습니다. 스프링 부트의 등장 2014년, 스프링 팀은 이런 문제를 해결하기 위해 스프링 부트를 출시했습니다.
스프링 부트의 철학은 간단합니다. "설정보다 관례(Convention over Configuration)"입니다.
마치 자동차의 자동 변속기처럼, 대부분의 설정을 자동으로 처리해주는 것입니다. 운전자가 일일이 기어를 변속하지 않아도 자동차가 알아서 최적의 기어를 선택하듯이, 개발자가 일일이 설정을 작성하지 않아도 스프링 부트가 알아서 최적의 설정을 적용합니다.
어떻게 자동화할까 스프링 부트는 **자동 설정(Auto Configuration)**이라는 마법을 사용합니다. 예를 들어 프로젝트에 H2 데이터베이스 라이브러리가 있으면, 스프링 부트는 자동으로 "아, 개발자가 H2 데이터베이스를 사용하고 싶구나"라고 판단합니다.
그리고 DataSource, JPA, TransactionManager 등을 자동으로 설정해줍니다. 개발자는 단지 필요한 라이브러리를 추가하기만 하면 됩니다.
나머지는 스프링 부트가 알아서 처리합니다. 임베디드 서버의 편리함 또 하나의 혁명은 임베디드 서버입니다.
전통적인 스프링 애플리케이션은 Tomcat 같은 웹 서버에 WAR 파일을 배포해야 했습니다. 서버를 설치하고, 설정하고, WAR 파일을 배포하는 복잡한 과정이 필요했습니다.
스프링 부트는 Tomcat을 애플리케이션 안에 포함시켰습니다. 마치 냉장고에 얼음 제조기가 내장된 것처럼, 웹 서버가 애플리케이션 안에 들어있습니다.
이제 개발자는 Java 명령어 하나로 애플리케이션을 실행할 수 있습니다. 별도의 서버 설치가 필요 없습니다.
실무에서의 활용 김개발 씨가 물었습니다. "그래서 실무에서는 어떻게 사용하나요?" 박시니어 씨가 화면을 가리키며 설명했습니다.
"보세요. 위의 코드가 전부입니다.
@SpringBootApplication 어노테이션 하나와 main 메서드 하나면 스프링 부트 애플리케이션이 완성됩니다." @SpringBootApplication은 세 가지 어노테이션을 합친 것입니다. @Configuration은 설정 클래스임을 나타내고, @EnableAutoConfiguration은 자동 설정을 활성화하며, @ComponentScan은 컴포넌트를 자동으로 찾아줍니다.
SpringApplication.run() 메서드는 애플리케이션을 실행합니다. 이 한 줄이 실행되면 임베디드 Tomcat 서버가 시작되고, 모든 빈이 등록되며, 애플리케이션이 동작하기 시작합니다.
빠른 개발 속도 스프링 부트의 가장 큰 장점은 개발 속도입니다. 예전에는 새 프로젝트를 시작할 때 하루 이틀이 걸렸습니다.
설정 파일을 작성하고, 서버를 설정하고, 테스트하는 과정이 필요했습니다. 지금은 5분이면 충분합니다.
Spring Initializr에서 프로젝트를 생성하고, IDE로 열어서 실행하면 끝입니다. "Hello World"를 출력하는 것이 아니라 실제로 동작하는 웹 애플리케이션이 완성됩니다.
스타트업의 선택 많은 스타트업이 스프링 부트를 선택하는 이유가 바로 이것입니다. 시장에 빠르게 제품을 출시해야 하는 스타트업에게 개발 속도는 생명입니다.
설정에 일주일을 쓰는 것보다 비즈니스 로직에 일주일을 쓰는 것이 훨씬 가치 있습니다. 네이버, 카카오, 쿠팡 같은 국내 대기업들도 스프링 부트를 적극적으로 사용하고 있습니다.
배우기 쉬운 스프링 김개발 씨가 안도의 한숨을 쉬었습니다. "그럼 저 같은 초보자도 쉽게 배울 수 있겠네요?" 박시니어 씨가 고개를 끄덕였습니다.
"맞아요. 스프링 부트 덕분에 스프링의 진입 장벽이 많이 낮아졌어요.
복잡한 설정을 몰라도 실제 동작하는 애플리케이션을 만들 수 있죠." 스프링 부트를 사용하면 스프링의 핵심 개념에 집중할 수 있습니다. 의존성 주입(DI), 제어의 역전(IoC), 관점 지향 프로그래밍(AOP) 같은 중요한 개념을 먼저 배우고, 설정은 나중에 필요할 때 배워도 됩니다.
실전 팁
💡 - @SpringBootApplication 하나면 스프링 부트 애플리케이션의 시작점이 완성됩니다
- 설정보다는 비즈니스 로직에 집중하세요. 필요한 설정만 나중에 추가하면 됩니다
- application.properties 파일 하나로 대부분의 설정을 관리할 수 있습니다
2. Spring Initializr 사용법
다음 날, 김개발 씨는 직접 스프링 부트 프로젝트를 만들어보기로 했습니다. 박시니어 씨가 말했습니다.
"직접 설정하지 말고 Spring Initializr를 사용해보세요." 이게 뭘까요?
Spring Initializr는 스프링 부트 프로젝트를 자동으로 생성해주는 웹 기반 도구입니다. 마치 레고 블록을 선택하듯이 필요한 기능을 체크하면, 완성된 프로젝트 구조를 다운로드할 수 있습니다.
복잡한 설정 없이 클릭 몇 번으로 프로젝트를 시작할 수 있습니다.
다음 코드를 살펴봅시다.
// Spring Initializr로 생성된 build.gradle 파일
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.0'
id 'io.spring.dependency-management' version '1.1.4'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
dependencies {
// Spring Initializr에서 선택한 의존성들이 자동으로 추가됨
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'com.h2database:h2'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
김개발 씨가 박시니어 씨의 모니터를 들여다봤습니다. 화면에는 start.spring.io라는 웹사이트가 열려 있었습니다.
"이게 Spring Initializr예요. 스프링 팀에서 만든 공식 프로젝트 생성기죠." 프로젝트 생성의 어려움 옛날 이야기를 해볼까요.
스프링 부트 이전 시대에는 새 프로젝트를 시작하는 것이 정말 어려웠습니다. 먼저 Maven이나 Gradle 설정 파일을 작성해야 했습니다.
어떤 라이브러리가 필요한지, 버전은 어떻게 맞춰야 하는지 일일이 찾아봐야 했습니다. 라이브러리 간 버전 충돌이 나면 해결하는 데 하루가 걸리기도 했습니다.
디렉토리 구조도 직접 만들어야 했습니다. src/main/java, src/main/resources, src/test/java...
하나라도 빠뜨리면 프로젝트가 제대로 동작하지 않았습니다. 초보 개발자들은 "Hello World"를 출력하기도 전에 지쳐버렸습니다.
Spring Initializr의 등장 스프링 팀은 이 문제를 해결하기 위해 Spring Initializr를 만들었습니다. 마치 맥도날드에서 햄버거를 주문하듯이, 웹사이트에서 원하는 옵션을 선택하면 완성된 프로젝트를 받을 수 있습니다.
"빅맥 세트 하나요? 콜라는 빼주세요." 이런 식으로 주문하는 것처럼 간단합니다.
사용 방법 - 단계별 가이드 박시니어 씨가 화면을 가리키며 설명했습니다. "자, 하나씩 선택해볼게요." 첫 번째는 프로젝트 타입입니다.
Maven과 Gradle 중 하나를 선택합니다. 요즘은 Gradle을 많이 사용합니다.
빌드 속도가 빠르고 설정이 간결하기 때문입니다. 두 번째는 언어입니다.
Java, Kotlin, Groovy 중 선택할 수 있습니다. 일반적으로 Java를 선택합니다.
세 번째는 스프링 부트 버전입니다. SNAPSHOT이나 M(Milestone) 표시가 없는 최신 안정 버전을 선택하는 것이 좋습니다.
현재는 3.2.0이 최신 안정 버전입니다. 프로젝트 메타데이터 입력 다음은 프로젝트 정보를 입력합니다.
Group은 회사나 조직의 도메인을 역순으로 적습니다. 예를 들어 회사 도메인이 example.com이면 com.example로 적습니다.
이것은 자바의 패키지 명명 규칙입니다. Artifact는 프로젝트 이름입니다.
예를 들어 쇼핑몰을 만든다면 "shopping-mall"처럼 적습니다. 이것이 최종 JAR 파일의 이름이 됩니다.
Name은 애플리케이션의 메인 클래스 이름이 됩니다. 보통 Artifact를 카멜케이스로 변환한 이름을 사용합니다.
의존성 선택 - 가장 중요한 단계 여기가 핵심입니다. 어떤 기능이 필요한지 선택하는 단계입니다.
"Add Dependencies" 버튼을 클릭하면 수백 개의 옵션이 나타납니다. 처음 보는 사람은 어지러울 수 있습니다.
하지만 걱정하지 마세요. 웹 애플리케이션을 만든다면 Spring Web을 선택합니다.
이것만 있으면 REST API를 만들 수 있습니다. 데이터베이스를 사용한다면 Spring Data JPA를 선택합니다.
그리고 사용할 데이터베이스 드라이버도 함께 선택합니다. 개발 단계에서는 H2 Database가 편리합니다.
별도 설치 없이 메모리에서 동작하는 데이터베이스입니다. 개발 도구로 Spring Boot DevTools를 추가하면 코드를 수정할 때마다 자동으로 재시작됩니다.
개발 속도가 크게 향상됩니다. 프로젝트 생성과 다운로드 모든 선택이 끝났으면 "Generate" 버튼을 클릭합니다.
그러면 ZIP 파일이 다운로드됩니다. 이 파일의 크기는 고작 수십 KB에 불과합니다.
"이게 전부인가요?"라고 놀랄 수 있습니다. 맞습니다.
실제 라이브러리는 포함되어 있지 않습니다. build.gradle 파일에 의존성 목록만 적혀 있습니다.
프로젝트를 열면 Gradle이 자동으로 필요한 라이브러리를 다운로드합니다. IDE에서 열기 ZIP 파일을 압축 해제하고 IntelliJ나 Eclipse에서 열면 됩니다.
IntelliJ에서는 "Open"을 선택하고 프로젝트 폴더를 선택하면 됩니다. IDE가 자동으로 Gradle 프로젝트임을 인식하고 필요한 라이브러리를 다운로드합니다.
처음에는 인터넷에서 라이브러리를 다운로드하느라 시간이 좀 걸립니다. 커피 한 잔 마시고 오면 준비가 완료되어 있습니다.
바로 실행 가능 놀라운 점은 바로 실행 가능하다는 것입니다. 메인 클래스를 열어서 Run 버튼을 클릭하면 애플리케이션이 시작됩니다.
별도의 설정이나 수정 없이 그대로 실행됩니다. 콘솔에 "Tomcat started on port 8080"이라는 메시지가 나타납니다.
웹 브라우저에서 localhost:8080에 접속하면 스프링 부트의 기본 에러 페이지가 나타납니다. 이것은 정상입니다.
아직 컨트롤러를 만들지 않았기 때문입니다. IDE 플러그인 활용 김개발 씨가 물었습니다.
"매번 웹사이트에 접속해야 하나요?" 박시니어 씨가 고개를 저었습니다. "아니요.
IntelliJ에는 Spring Initializr가 통합되어 있어요." IntelliJ에서 "New Project"를 선택하면 Spring Initializr 옵션이 있습니다. 같은 화면이 IDE 안에서 나타납니다.
웹사이트에 접속할 필요 없이 IDE에서 바로 프로젝트를 생성할 수 있습니다. 실무 활용 팁 실무에서는 회사마다 표준 프로젝트 템플릿이 있는 경우가 많습니다.
하지만 새로운 프로젝트를 시작하거나, 학습용 프로젝트를 만들 때는 Spring Initializr가 최고의 선택입니다. 단 5분 만에 실무 수준의 프로젝트 구조를 얻을 수 있습니다.
실전 팁
💡 - start.spring.io에서 Gradle + Java + 최신 안정 버전을 선택하세요
- 처음에는 Spring Web, Spring Data JPA, H2 Database만 선택하고 시작하세요
- IntelliJ Ultimate 버전은 IDE 안에서 직접 Spring Initializr를 사용할 수 있습니다
3. 프로젝트 구조 이해
프로젝트를 생성한 김개발 씨가 폴더 구조를 보며 고개를 갸우뚱했습니다. "이 폴더들은 뭐고, 이 파일들은 왜 필요한 거죠?" 박시니어 씨가 웃으며 말했습니다.
"프로젝트 구조를 이해하면 스프링 부트가 어떻게 동작하는지 알 수 있어요."
스프링 부트 프로젝트 구조는 일정한 규칙을 따릅니다. 마치 아파트의 설계도처럼, 어디에 무엇을 배치해야 하는지 정해져 있습니다.
src/main/java에는 소스 코드가, src/main/resources에는 설정 파일이 들어갑니다. 이 구조를 이해하면 어디에 어떤 파일을 만들어야 할지 자연스럽게 알게 됩니다.
다음 코드를 살펴봅시다.
// 전형적인 스프링 부트 프로젝트 구조
my-project/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/example/demo/
│ │ │ ├── DemoApplication.java // 메인 클래스
│ │ │ ├── controller/ // 컨트롤러 패키지
│ │ │ ├── service/ // 서비스 패키지
│ │ │ ├── repository/ // 리포지토리 패키지
│ │ │ └── domain/ // 엔티티 패키지
│ │ └── resources/
│ │ ├── application.yml // 설정 파일
│ │ ├── static/ // 정적 리소스
│ │ └── templates/ // 템플릿 파일
│ └── test/ // 테스트 코드
└── build.gradle // 빌드 설정
박시니어 씨가 프로젝트 탐색기를 펼쳐 보였습니다. 김개발 씨는 여러 폴더와 파일들을 보며 막막함을 느꼈습니다.
"처음엔 다들 그래요. 하지만 구조는 생각보다 단순해요." Maven 표준 디렉토리 구조 스프링 부트는 Maven 표준 디렉토리 구조를 따릅니다.
이것은 자바 진영에서 오랫동안 사용해온 검증된 구조입니다. 마치 도로 교통 신호가 전 세계적으로 비슷하듯이, 자바 프로젝트도 비슷한 구조를 사용합니다.
이 덕분에 처음 보는 프로젝트라도 구조를 금방 파악할 수 있습니다. "아, 컨트롤러는 controller 패키지에 있겠구나" 하고 직관적으로 알 수 있습니다.
src 폴더 - 모든 것의 시작 최상위에는 src 폴더가 있습니다. Source의 약자입니다.
여기에는 모든 소스 코드와 리소스가 들어갑니다. src 폴더 밖에는 빌드 설정 파일(build.gradle, pom.xml)과 프로젝트 설정 파일들만 있습니다.
마치 집에서 거실, 방, 주방이 안에 있고, 현관문은 밖에 있는 것과 비슷합니다. main과 test의 분리 src 폴더 안을 보면 main과 test 폴더가 있습니다.
main 폴더에는 실제 애플리케이션 코드가 들어갑니다. 고객에게 전달되는 최종 제품의 코드입니다.
test 폴더에는 테스트 코드가 들어갑니다. 개발 중에는 사용되지만 최종 제품에는 포함되지 않습니다.
이렇게 분리하는 이유는 명확합니다. 테스트 코드는 빌드할 때 제외할 수 있어야 합니다.
고객에게 전달하는 JAR 파일에 테스트 코드가 포함될 필요는 없기 때문입니다. java 폴더 - 소스 코드의 집 main 폴더 안에는 java와 resources 폴더가 있습니다.
java 폴더에는 모든 자바 소스 코드가 들어갑니다. .java 확장자를 가진 파일들이 여기에 위치합니다.
이 폴더의 최상위에는 패키지 구조가 시작됩니다. 예를 들어 Group을 com.example로 설정했다면 com/example 폴더가 생성됩니다.
메인 클래스의 위치 가장 중요한 파일은 메인 클래스입니다. @SpringBootApplication 어노테이션이 붙은 이 클래스는 패키지의 루트에 위치해야 합니다.
예를 들어 com.example.demo 패키지라면, 이 패키지의 최상위에 DemoApplication.java가 있어야 합니다. 왜 그럴까요?
@SpringBootApplication은 자동으로 같은 패키지와 하위 패키지를 스캔하기 때문입니다. 메인 클래스를 루트에 두면 모든 하위 패키지의 컴포넌트를 자동으로 찾을 수 있습니다.
패키지 구조 - 계층별 분류 메인 클래스 아래에는 여러 하위 패키지를 만듭니다. controller 패키지에는 컨트롤러 클래스들이 들어갑니다.
HTTP 요청을 받아서 처리하는 클래스들입니다. service 패키지에는 비즈니스 로직을 담당하는 서비스 클래스들이 들어갑니다.
실제 업무 규칙이 구현되는 곳입니다. repository 패키지에는 데이터베이스 접근을 담당하는 리포지토리 인터페이스들이 들어갑니다.
domain 또는 entity 패키지에는 엔티티 클래스들이 들어갑니다. 데이터베이스 테이블과 매핑되는 클래스들입니다.
이것을 **계층 구조(Layered Architecture)**라고 합니다. 각 계층이 명확한 역할을 가지고 있습니다.
resources 폴더 - 설정과 리소스 resources 폴더에는 자바 코드가 아닌 모든 것이 들어갑니다. 가장 중요한 파일은 application.properties 또는 application.yml입니다.
데이터베이스 연결 정보, 서버 포트 번호 등 모든 설정이 이 파일에 들어갑니다. static 폴더에는 CSS, JavaScript, 이미지 같은 정적 파일이 들어갑니다.
웹 브라우저에 그대로 전달되는 파일들입니다. templates 폴더에는 Thymeleaf 같은 템플릿 파일이 들어갑니다.
동적으로 HTML을 생성할 때 사용됩니다. 빌드 폴더 - 자동 생성 프로젝트를 빌드하면 build 폴더(Gradle) 또는 target 폴더(Maven)가 생성됩니다.
여기에는 컴파일된 클래스 파일과 최종 JAR 파일이 들어갑니다. 이 폴더는 자동으로 생성되므로 직접 수정할 필요가 없습니다.
.gitignore 파일을 보면 이 폴더들이 포함되어 있습니다. 빌드 결과물은 Git에 커밋하지 않습니다.
설정 파일들 프로젝트 루트에는 여러 설정 파일이 있습니다. build.gradle은 Gradle 빌드 설정 파일입니다.
의존성 목록과 빌드 스크립트가 들어있습니다. settings.gradle은 프로젝트 이름과 멀티 모듈 설정이 들어있습니다.
.gitignore는 Git이 무시할 파일 목록입니다. IDE 설정 파일이나 빌드 결과물을 커밋하지 않도록 합니다.
실무에서의 확장 실제 프로젝트에서는 이 기본 구조를 확장해서 사용합니다. 예를 들어 dto 패키지를 만들어 Data Transfer Object를 관리하거나, config 패키지를 만들어 설정 클래스를 모아둡니다.
exception 패키지에는 커스텀 예외 클래스들을 넣습니다. 하지만 기본 구조는 동일합니다.
controller, service, repository, domain이라는 핵심 계층은 거의 모든 프로젝트에서 사용됩니다. 왜 이런 구조를 사용할까 김개발 씨가 물었습니다.
"왜 이렇게 복잡하게 나누는 건가요?" 박시니어 씨가 답했습니다. "관심사의 분리 때문입니다.
각 계층이 자기 역할만 하면 코드가 깔끔해지고 유지보수가 쉬워집니다." 컨트롤러는 HTTP 요청 처리만, 서비스는 비즈니스 로직만, 리포지토리는 데이터 접근만 담당합니다. 나중에 데이터베이스를 바꾸더라도 리포지토리만 수정하면 됩니다.
실전 팁
💡 - 메인 클래스는 항상 패키지의 최상위에 위치시키세요. 하위 패키지의 컴포넌트를 자동으로 스캔합니다
- controller, service, repository, domain 패키지 구조는 스프링 부트의 사실상 표준입니다
- resources 폴더의 application.yml은 모든 설정의 중심입니다
4. application yml 설정
김개발 씨가 데이터베이스를 연결하려다가 막혔습니다. "어디서 설정하는 거죠?" 박시니어 씨가 application.yml 파일을 열며 말했습니다.
"스프링 부트의 모든 설정은 여기서 합니다."
application.yml은 스프링 부트 애플리케이션의 설정을 관리하는 파일입니다. 마치 리모컨의 설정 메뉴처럼, 서버 포트부터 데이터베이스 연결까지 모든 것을 한 곳에서 제어할 수 있습니다.
YAML 형식을 사용하여 계층적이고 읽기 쉬운 설정을 작성할 수 있습니다.
다음 코드를 살펴봅시다.
# application.yml - 스프링 부트 설정 파일
spring:
# 데이터베이스 설정
datasource:
url: jdbc:h2:mem:testdb
driver-class-name: org.h2.Driver
username: sa
password:
# JPA 설정
jpa:
hibernate:
ddl-auto: create-drop
show-sql: true
properties:
hibernate:
format_sql: true
# 서버 설정
server:
port: 8080
# 로깅 설정
logging:
level:
com.example.demo: debug
박시니어 씨가 resources 폴더의 application.yml 파일을 열었습니다. 김개발 씨는 깔끔하게 정리된 설정을 보며 감탄했습니다.
"이게 스프링 부트의 핵심 설정 파일입니다." 설정 파일의 진화 옛날 스프링 프로젝트는 XML 설정 파일을 사용했습니다. 수백 줄의 XML 태그가 중첩되어 있었고, 한 글자라도 잘못 쓰면 오류가 났습니다.
닫는 태그를 빠뜨리거나, 속성 이름을 잘못 쓰는 실수가 빈번했습니다. 스프링 부트는 이 문제를 해결하기 위해 application.properties 파일을 도입했습니다.
키=값 형태로 간단하게 설정할 수 있었습니다. 하지만 더 나은 방법이 있었습니다.
YAML 형식입니다. YAML이 뭔가요 YAML은 "YAML Ain't Markup Language"의 약자입니다.
들여쓰기로 계층 구조를 표현하는 데이터 직렬화 형식입니다. 마치 파이썬 코드처럼 들여쓰기가 중요합니다.
XML보다 간결하고, JSON보다 읽기 쉽습니다. 사람이 직접 작성하고 읽기에 최적화되어 있습니다.
기본 문법 YAML의 기본 문법은 간단합니다. 키와 값은 콜론(:)으로 구분합니다.
계층 구조는 들여쓰기로 표현합니다. 들여쓰기는 스페이스 2칸을 사용하는 것이 관례입니다.
예를 들어 "spring.datasource.url"이라는 키는 YAML에서 이렇게 표현됩니다. spring 아래에 datasource가 있고, 그 아래에 url이 있는 구조입니다.
데이터베이스 설정 가장 흔히 사용하는 설정은 데이터베이스 연결입니다. spring.datasource 아래에 url, driver-class-name, username, password를 설정합니다.
url은 데이터베이스 연결 주소입니다. jdbc:h2:mem:testdb는 H2 메모리 데이터베이스를 의미합니다.
애플리케이션이 종료되면 데이터가 사라지지만 개발 단계에서는 편리합니다. driver-class-name은 JDBC 드라이버 클래스입니다.
H2를 사용한다면 org.h2.Driver를 지정합니다. username과 password는 데이터베이스 인증 정보입니다.
H2의 기본 사용자는 sa이고 비밀번호는 비어있습니다. JPA 설정 데이터베이스를 사용한다면 JPA 설정도 필요합니다.
spring.jpa.hibernate.ddl-auto는 테이블 자동 생성 전략입니다. create-drop을 설정하면 애플리케이션 시작 시 테이블을 생성하고, 종료 시 삭제합니다.
개발 단계에서 유용합니다. 운영 환경에서는 절대 create-drop을 사용하면 안 됩니다.
데이터가 모두 삭제됩니다. 운영에서는 validate나 none을 사용합니다.
spring.jpa.show-sql을 true로 설정하면 실행되는 SQL을 콘솔에 출력합니다. 어떤 쿼리가 실행되는지 확인할 수 있어서 학습에 도움이 됩니다.
서버 설정 server.port는 웹 서버가 사용할 포트 번호입니다. 기본값은 8080입니다.
하지만 8080 포트가 이미 사용 중이라면 다른 번호로 변경할 수 있습니다. 예를 들어 9090이나 3000을 사용할 수 있습니다.
server.servlet.context-path를 설정하면 애플리케이션의 기본 경로를 변경할 수 있습니다. 예를 들어 /api로 설정하면 모든 URL이 /api로 시작됩니다.
로깅 설정 개발 중에는 로그가 매우 중요합니다. logging.level을 사용하면 패키지별로 로그 레벨을 설정할 수 있습니다.
debug, info, warn, error 중 선택합니다. 예를 들어 자신의 패키지는 debug로 설정하고, 외부 라이브러리는 info로 설정할 수 있습니다.
불필요한 로그를 줄여서 중요한 정보만 볼 수 있습니다. 프로파일 - 환경별 설정 개발 환경과 운영 환경의 설정은 다릅니다.
개발에서는 H2 메모리 데이터베이스를 사용하지만, 운영에서는 MySQL이나 PostgreSQL을 사용합니다. 로그 레벨도 다릅니다.
이럴 때 프로파일을 사용합니다. application-dev.yml과 application-prod.yml을 따로 만듭니다.
실행할 때 spring.profiles.active=dev처럼 프로파일을 지정하면 해당 설정 파일이 적용됩니다. 환경 변수 사용 민감한 정보는 설정 파일에 직접 쓰면 안 됩니다.
데이터베이스 비밀번호나 API 키 같은 정보를 Git에 커밋하면 보안 문제가 생깁니다. 이럴 때는 환경 변수를 사용합니다.
${DB_PASSWORD}처럼 작성하면 환경 변수의 값을 읽어옵니다. 자동 완성의 힘 IntelliJ 같은 IDE는 application.yml에서 자동 완성을 지원합니다.
spring.을 입력하고 Ctrl+Space를 누르면 사용 가능한 설정 목록이 나타납니다. 각 설정의 설명도 볼 수 있습니다.
이것은 스프링 부트가 메타데이터를 제공하기 때문입니다. 설정 가능한 모든 속성의 정보가 라이브러리에 포함되어 있습니다.
실무 활용 팁 김개발 씨가 물었습니다. "어떤 설정을 자주 사용하나요?" 박시니어 씨가 답했습니다.
"프로젝트마다 다르지만, 데이터베이스 설정, JPA 설정, 서버 포트는 거의 항상 설정합니다." 또한 spring.jackson을 사용하여 JSON 직렬화 옵션을 제어하거나, spring.mvc로 웹 MVC 동작을 커스터마이징할 수 있습니다. 설정의 우선순위 여러 곳에서 같은 설정을 할 수 있습니다.
application.yml 파일, 환경 변수, 커맨드 라인 인자 등 다양한 방법이 있습니다. 이들 간에는 우선순위가 있습니다.
일반적으로 커맨드 라인 인자가 가장 높고, 환경 변수, 설정 파일 순서입니다. 이를 통해 기본값을 파일에 두고, 필요할 때 환경 변수로 오버라이드할 수 있습니다.
실전 팁
💡 - application.yml은 들여쓰기가 중요합니다. 스페이스 2칸으로 통일하세요
- 민감한 정보는 환경 변수로 관리하고 Git에 커밋하지 마세요
- IDE의 자동 완성을 활용하면 사용 가능한 설정을 쉽게 찾을 수 있습니다
5. 스프링 부트 3 새로운 기능
커피를 마시며 김개발 씨가 물었습니다. "스프링 부트 3은 뭐가 달라졌나요?" 박시니어 씨가 모니터를 가리키며 말했습니다.
"많은 것이 바뀌었어요. 특히 자바 17이 필수가 되었죠."
스프링 부트 3은 스프링 부트 2에서 대대적으로 업그레이드된 버전입니다. 자바 17을 최소 버전으로 요구하며, Jakarta EE로의 전환, Native Image 지원, 관측성 개선 등 많은 변화가 있습니다.
마치 자동차의 신형 모델처럼, 기존 기능은 유지하면서 성능과 효율성이 크게 향상되었습니다.
다음 코드를 살펴봅시다.
// 스프링 부트 3의 새로운 기능 활용 예제
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.*;
// Jakarta EE - javax가 jakarta로 변경됨
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
@SpringBootApplication
public class SpringBoot3Demo {
public static void main(String[] args) {
SpringApplication.run(SpringBoot3Demo.class, args);
}
}
// 개선된 문제 상세 정보 (RFC 7807)
@RestController
class UserController {
@PostMapping("/users")
public String createUser(@Valid @RequestBody UserRequest request) {
// 자바 17의 Record 타입 사용 가능
return "User created: " + request.name();
}
}
record UserRequest(@NotBlank String name, int age) {}
박시니어 씨가 릴리스 노트를 열어 보였습니다. 김개발 씨는 많은 변경 사항에 놀랐습니다.
"스프링 부트 3은 2022년 11월에 출시되었어요. 거의 4년 만의 메이저 업데이트였죠." 자바 17 최소 요구 사항 가장 큰 변화는 자바 17이 최소 버전이 되었다는 것입니다.
자바 17은 LTS(Long Term Support) 버전입니다. 장기간 지원을 받을 수 있어서 안정적입니다.
하지만 자바 8이나 11을 사용하던 프로젝트는 업그레이드가 필요합니다. 왜 자바 17을 선택했을까요?
성능 향상, 새로운 언어 기능, 보안 개선 등 많은 이점이 있기 때문입니다. 자바 17의 새로운 기능 자바 17에는 유용한 기능이 많습니다.
Record 타입은 불변 데이터 클래스를 간단히 만들 수 있습니다. DTO를 작성할 때 getter, equals, hashCode를 자동으로 생성해줍니다.
Pattern Matching은 타입 검사와 캐스팅을 한 번에 처리합니다. if (obj instanceof String s)처럼 쓸 수 있어서 코드가 간결해집니다.
Text Blocks는 여러 줄 문자열을 쉽게 작성할 수 있습니다. SQL 쿼리나 JSON 문자열을 작성할 때 편리합니다.
Jakarta EE로의 전환 두 번째 큰 변화는 Jakarta EE로의 전환입니다. javax 패키지가 모두 jakarta로 바뀌었습니다.
import javax.servlet이 import jakarta.servlet이 되었습니다. 왜 이런 변화가 생겼을까요?
오라클이 Java EE를 이클립스 재단에 기부했기 때문입니다. 이클립스 재단은 상표권 문제로 이름을 Jakarta EE로 변경했습니다.
마이그레이션의 어려움 이것은 호환성을 깨는 변경입니다. 스프링 부트 2 프로젝트를 3으로 업그레이드하려면 모든 import 문을 수정해야 합니다.
IDE의 자동 리팩토링 기능을 사용하면 비교적 쉽게 처리할 수 있지만, 사용 중인 라이브러리가 Jakarta를 지원하는지 확인해야 합니다. Native Image 지원 세 번째 큰 변화는 GraalVM Native Image 지원입니다.
일반적인 자바 애플리케이션은 JVM 위에서 실행됩니다. 시작 시간이 느리고 메모리를 많이 사용합니다.
Native Image는 자바 코드를 네이티브 바이너리로 컴파일합니다. 마치 C나 Go로 만든 프로그램처럼 실행 파일이 생성됩니다.
Native Image의 장점 Native Image의 장점은 놀랍습니다. 시작 시간이 밀리초 단위로 줄어듭니다.
일반 스프링 부트 애플리케이션은 시작에 수 초가 걸리지만, Native Image는 0.1초 만에 시작됩니다. 메모리 사용량도 크게 줄어듭니다.
JVM 없이 실행되기 때문입니다. 클라우드 환경에서 비용 절감 효과가 큽니다.
관측성(Observability) 개선 네 번째 변화는 Micrometer와 Micrometer Tracing의 통합입니다. 관측성이란 애플리케이션의 상태를 외부에서 관찰할 수 있는 능력입니다.
로그, 메트릭, 트레이스를 통해 시스템을 이해합니다. 스프링 부트 3은 Actuator를 통해 강력한 관측성 기능을 제공합니다.
Prometheus, Grafana, Zipkin 같은 모니터링 도구와 쉽게 통합됩니다. 문제 상세 정보(Problem Details) 다섯 번째 변화는 RFC 7807 지원입니다.
REST API에서 오류를 반환할 때 표준화된 형식을 사용할 수 있습니다. 예전에는 개발자마다 다른 에러 응답 형식을 사용했습니다.
이제 ProblemDetail 클래스를 사용하면 표준 형식의 에러 응답을 자동으로 생성할 수 있습니다. Spring Authorization Server 여섯 번째 변화는 자체 인증 서버의 제공입니다.
OAuth 2.0과 OpenID Connect를 지원하는 인증 서버를 직접 구축할 수 있습니다. 더 이상 외부 인증 서비스에 의존하지 않아도 됩니다.
물론 Keycloak이나 Auth0 같은 전문 서비스를 사용할 수도 있지만, 간단한 프로젝트에서는 내장 인증 서버로 충분합니다. Spring for GraphQL 일곱 번째는 GraphQL 공식 지원입니다.
GraphQL은 REST의 대안으로 떠오르는 API 쿼리 언어입니다. 클라이언트가 필요한 데이터만 정확히 요청할 수 있습니다.
스프링 부트 3은 Spring for GraphQL을 통해 GraphQL 서버를 쉽게 구축할 수 있게 해줍니다. 성능 개선 여러 성능 개선도 이루어졌습니다.
자동 설정이 더 빨라졌고, 메모리 사용량이 줄어들었습니다. 특히 애플리케이션 시작 시간이 스프링 부트 2보다 약 20% 빨라졌습니다.
마이그레이션 가이드 김개발 씨가 걱정스럽게 물었습니다. "기존 프로젝트를 업그레이드하려면 어떻게 해야 하나요?" 박시니어 씨가 답했습니다.
"공식 마이그레이션 가이드를 따라하면 됩니다." 먼저 자바 버전을 17로 업그레이드합니다. 그다음 javax를 jakarta로 변경합니다.
마지막으로 deprecated된 API를 새 API로 교체합니다. 언제 업그레이드해야 할까 새 프로젝트는 당연히 스프링 부트 3을 사용해야 합니다.
기존 프로젝트는 신중하게 결정해야 합니다. 스프링 부트 2는 2025년까지 지원됩니다.
하지만 장기적으로는 업그레이드가 필요합니다. 특히 Native Image나 최신 자바 기능을 사용하고 싶다면 스프링 부트 3으로의 전환을 고려해야 합니다.
실전 팁
💡 - 새 프로젝트는 스프링 부트 3과 자바 17 이상을 사용하세요
- javax를 jakarta로 변경하는 것을 잊지 마세요. IDE의 자동 리팩토링 기능을 활용하세요
- Native Image는 클라우드 환경에서 비용 절감 효과가 큽니다
6. 의존성 관리
마지막 날, 김개발 씨가 새로운 라이브러리를 추가하려다가 버전 충돌 에러를 만났습니다. "왜 이런 에러가 나는 거죠?" 박시니어 씨가 build.gradle을 열며 설명했습니다.
"의존성 관리를 이해해야 합니다."
의존성 관리는 프로젝트에 필요한 라이브러리를 관리하는 것입니다. 스프링 부트는 Starter를 통해 관련된 라이브러리를 한 번에 추가할 수 있게 해줍니다.
마치 컴퓨터를 살 때 번들 패키지를 선택하는 것처럼, 필요한 라이브러리 세트를 간편하게 가져올 수 있습니다.
다음 코드를 살펴봅시다.
// build.gradle - 스프링 부트의 의존성 관리
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.0'
id 'io.spring.dependency-management' version '1.1.4'
}
dependencies {
// Starter를 사용한 의존성 추가 - 버전을 명시하지 않음
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
// 데이터베이스 드라이버 - 런타임에만 필요
runtimeOnly 'com.h2database:h2'
// 테스트 의존성 - 테스트 시에만 사용
testImplementation 'org.springframework.boot:spring-boot-starter-test'
// 특정 버전을 명시적으로 지정할 수도 있음
implementation 'com.google.code.gson:gson:2.10.1'
}
박시니어 씨가 build.gradle 파일의 dependencies 섹션을 가리켰습니다. 김개발 씨는 버전 번호가 없는 것을 보고 놀랐습니다.
"왜 버전을 안 쓰는 건가요?" 의존성 지옥 옛날 자바 프로젝트는 의존성 지옥으로 악명 높았습니다. 라이브러리 A는 Commons Lang 2.6을 요구하고, 라이브러리 B는 Commons Lang 3.1을 요구합니다.
둘을 함께 사용하려면 버전 충돌이 발생합니다. 개발자는 호환되는 버전 조합을 찾느라 며칠을 허비했습니다.
한 라이브러리의 버전을 올리면 다른 곳에서 문제가 생겼습니다. 스프링 부트의 해결책 스프링 부트는 이 문제를 **BOM(Bill of Materials)**으로 해결했습니다.
BOM은 호환되는 라이브러리 버전의 목록입니다. 마치 레시피처럼, "이 재료들을 이 비율로 섞으면 맛있는 요리가 됩니다"라고 알려줍니다.
spring-boot-dependencies BOM에는 수백 개의 라이브러리 버전이 정의되어 있습니다. 스프링 팀이 테스트를 거쳐 호환성을 보장한 버전들입니다.
Starter의 마법 Starter는 관련된 라이브러리를 묶어놓은 패키지입니다. spring-boot-starter-web을 추가하면 무엇이 들어올까요?
Spring MVC, Tomcat, Jackson, Validation 등 웹 애플리케이션에 필요한 모든 것이 함께 들어옵니다. 직접 하나씩 추가할 필요가 없습니다.
Starter 하나면 충분합니다. 그리고 모든 라이브러리의 버전이 자동으로 맞춰집니다.
주요 Starter들 자주 사용하는 Starter를 알아볼까요. spring-boot-starter-web은 웹 애플리케이션 개발에 필요한 모든 것을 제공합니다.
REST API를 만들 때 필수입니다. spring-boot-starter-data-jpa는 JPA와 Hibernate를 포함합니다.
데이터베이스 작업이 훨씬 쉬워집니다. spring-boot-starter-security는 인증과 권한 부여 기능을 제공합니다.
보안이 필요한 애플리케이션에 사용합니다. spring-boot-starter-test는 JUnit, Mockito, AssertJ 등 테스트 도구를 포함합니다.
테스트 코드 작성에 필요한 모든 것이 들어있습니다. 의존성 스코프 의존성에는 스코프가 있습니다.
implementation은 컴파일과 런타임에 모두 필요한 의존성입니다. 대부분의 라이브러리가 여기에 속합니다.
runtimeOnly는 런타임에만 필요한 의존성입니다. 데이터베이스 드라이버가 대표적입니다.
컴파일할 때는 인터페이스만 있으면 되고, 실행할 때 실제 드라이버가 필요합니다. testImplementation은 테스트 코드에서만 사용하는 의존성입니다.
최종 제품에는 포함되지 않습니다. compileOnly는 컴파일할 때만 필요한 의존성입니다.
Lombok이 대표적입니다. 컴파일 시 코드를 생성하고, 런타임에는 필요 없습니다.
버전 오버라이드 때로는 스프링 부트가 제공하는 버전을 사용하고 싶지 않을 수 있습니다. 이럴 때는 명시적으로 버전을 지정하면 됩니다.
implementation 'com.google.code.gson:gson:2.10.1'처럼 버전을 명시하면 BOM의 버전을 무시합니다. 하지만 주의해야 합니다.
다른 라이브러리와 충돌이 생길 수 있습니다. 꼭 필요한 경우에만 버전을 오버라이드하세요.
전이적 의존성 라이브러리는 또 다른 라이브러리에 의존합니다. spring-boot-starter-web은 spring-web에 의존하고, spring-web은 spring-core에 의존합니다.
이것을 **전이적 의존성(Transitive Dependency)**이라고 합니다. Gradle이나 Maven은 전이적 의존성을 자동으로 처리합니다.
우리는 최상위 Starter만 추가하면 되고, 나머지는 빌드 도구가 알아서 가져옵니다. 의존성 확인 어떤 라이브러리가 실제로 포함되었는지 확인하고 싶을 때가 있습니다.
Gradle에서는 ./gradlew dependencies 명령을 실행하면 의존성 트리를 볼 수 있습니다. 어떤 라이브러리가 어떤 버전으로 포함되었는지, 어디서 가져온 것인지 모두 확인할 수 있습니다.
IntelliJ에는 Gradle 탭에 의존성을 시각적으로 보여주는 기능이 있습니다. 클릭 몇 번으로 전체 의존성 구조를 파악할 수 있습니다.
충돌 해결 그래도 가끔 충돌이 발생합니다. 두 라이브러리가 같은 의존성의 다른 버전을 요구하면 어떻게 될까요?
Gradle은 기본적으로 가장 높은 버전을 선택합니다. 이것이 문제가 되면 명시적으로 버전을 지정하거나, exclude를 사용하여 특정 의존성을 제외할 수 있습니다.
실무 팁 김개발 씨가 물었습니다. "실무에서는 어떻게 관리하나요?" 박시니어 씨가 답했습니다.
"가능한 한 스프링 부트의 BOM을 신뢰하세요. 스프링 팀이 이미 테스트한 조합입니다." 새로운 라이브러리를 추가할 때는 먼저 스프링 부트가 관리하는 버전이 있는지 확인하세요.
dependencies 명령으로 현재 관리되는 버전을 확인할 수 있습니다. 보안 업데이트 의존성 관리는 보안과도 관련이 있습니다.
오래된 라이브러리는 보안 취약점이 있을 수 있습니다. 스프링 부트를 최신 버전으로 유지하면 대부분의 라이브러리도 자동으로 업데이트됩니다.
GitHub의 Dependabot이나 Snyk 같은 도구를 사용하면 취약한 의존성을 자동으로 감지하고 PR을 생성해줍니다. 마지막 조언 박시니어 씨가 마무리하며 말했습니다.
"의존성은 적을수록 좋습니다. 정말 필요한 것만 추가하세요." 많은 라이브러리를 추가하면 빌드 시간이 늘어나고, 보안 위험도 커지며, 라이선스 문제도 복잡해집니다.
꼭 필요한 것만 선별해서 사용하세요. 김개발 씨는 일주일 동안 많은 것을 배웠습니다.
이제 스프링 부트로 실제 프로젝트를 시작할 준비가 되었습니다.
실전 팁
💡 - 가능한 한 Starter를 사용하고 버전을 명시하지 마세요. 스프링 부트가 호환되는 버전을 자동으로 관리합니다
- ./gradlew dependencies 명령으로 실제 포함된 의존성을 확인할 수 있습니다
- 의존성은 최소한으로 유지하세요. 정말 필요한 것만 추가하는 것이 좋습니다
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
관찰 가능한 마이크로서비스 완벽 가이드
마이크로서비스 환경에서 시스템의 상태를 실시간으로 관찰하고 모니터링하는 방법을 배웁니다. Resilience4j, Zipkin, Prometheus, Grafana, EFK 스택을 활용하여 안정적이고 관찰 가능한 시스템을 구축하는 실전 가이드입니다.
Prometheus 메트릭 수집 완벽 가이드
Spring Boot 애플리케이션의 메트릭을 Prometheus로 수집하고 모니터링하는 방법을 배웁니다. Actuator 설정부터 PromQL 쿼리까지 실무에 필요한 모든 내용을 다룹니다.
스프링 관찰 가능성 완벽 가이드
Spring Boot 3.x의 Observation API를 활용한 애플리케이션 모니터링과 추적 방법을 초급 개발자 눈높이에서 쉽게 설명합니다. 실무에서 바로 적용할 수 있는 메트릭 수집과 분산 추적 기법을 다룹니다.
Zipkin으로 추적 시각화 완벽 가이드
마이크로서비스 환경에서 분산 추적을 시각화하는 Zipkin의 핵심 개념과 활용 방법을 초급자도 쉽게 이해할 수 있도록 실무 스토리로 풀어낸 가이드입니다. Docker 실행부터 UI 분석까지 단계별로 배웁니다.
Micrometer Tracing 완벽 가이드
분산 시스템에서 요청 흐름을 추적하는 Micrometer Tracing의 핵심 개념과 실전 활용법을 초급 개발자도 쉽게 이해할 수 있도록 실무 스토리와 비유로 풀어낸 완벽 가이드입니다.