spring-boot-starter-web 한 줄이 47개 JAR을 끌고 오는 이유 — Starter와 설정 관리

build.gradleimplementation 'org.springframework.boot:spring-boot-starter-web' 한 줄을 추가했다. Gradle은 47개의 의존성을 다운로드한다 — Spring MVC, Jackson, Tomcat, Bean Validation, 로깅 등. 각각의 버전을 직접 맞출 필요 없이, Starter가 호환되는 버전 세트를 큐레이션한다.

이 글은 Starter 의존성의 구조, application.yml 외부화, 프로파일별 설정, 그리고 Spring Boot 4.0의 모듈화된 Starter 구조를 풀어간다. (Spring Boot Reference - Starters)

Starter — 의존성 큐레이션

Starter는 특정 기능에 필요한 모든 의존성을 하나의 의존성으로 묶은 메타 패키지다.

flowchart TD
    SW["spring-boot-starter-web"] --> MVC["spring-web-mvc"]
    SW --> TC["spring-boot-starter-tomcat"]
    SW --> JK["jackson-databind"]
    SW --> BV["spring-boot-starter-validation"]
    SW --> LG["spring-boot-starter-logging"]
    SW --> CORE["spring-boot-starter<br/>(core: Spring context, DI)"]
Starter 용도
spring-boot-starter Core (DI, 설정, 로깅)
spring-boot-starter-web REST API (MVC + Tomcat + Jackson)
spring-boot-starter-data-jpa JPA + Hibernate
spring-boot-starter-security Spring Security
spring-boot-starter-test 테스트 (JUnit 6, Mockito, AssertJ)
spring-boot-starter-actuator 모니터링, 헬스 체크

Starter는 버전 호환성을 보장한다 — Spring Boot 4.0.0에 포함된 Starter는 Spring Framework 7.0, Tomcat 11, Hibernate 7.x, Jackson 2.x 등 서로 호환되는 버전으로 고정된다. 개발자가 버전 충돌을 수동으로 해결할 필요가 없다.

비유: Starter는 정해진 코디 세트와 같다. "봄 출근 룩" 세트를 사면 — 자켓, 바지, 셔츠, 넥타이가 서로 어울리는 조합으로 큐레이션되어 나온다. 각각을 따로 사면 색상이나 사이즈가 안 맞을 수 있지만, 세트면 보장된다. spring-boot-starter-web 세트에는 Spring MVC + Tomcat + Jackson + Bean Validation이 서로 호환되는 버전으로 묶여 있다.

내부 구조: Starter는 실제 코드를 포함하지 않는다 — 의존성 목록만 있는 빈 JAR다. spring-boot-starter-webpom.xml(또는 build.gradle)에는 spring-web-mvc, spring-boot-starter-tomcat, jackson-databind 등의 의존성이 compile 스코프로 선언되어 있다. Gradle/Maven이 이를 전이적으로 끌어온다. "Starter = 의존성 BOM(Bill of Materials)"이다.

application.yml — 외부화된 설정

Spring Boot는 application.yml(또는 .properties)로 애플리케이션 설정을 외부화한다.

# Spring Boot 4 / Java 25 — application.yml
spring:
  application:
    name: my-service
  datasource:
    url: jdbc:postgresql://localhost:5432/mydb
    username: dbuser
    password: dbpass
    hikari:
      maximum-pool-size: 20
  jpa:
    hibernate:
      ddl-auto: validate
    show-sql: true
  threads:
    virtual:
      enabled: true   # Virtual Thread 활성화 (Spring Boot 3.2+)

server:
  port: 8080
  tomcat:
    threads:
      max: 200

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics

프로퍼티 계층 구조

Spring Boot는 17개 이상의 프로퍼티 소스를 계층적으로 관리한다 (우선순위 높은 것부터):

우선순위 소스
1 명령행 인자 --server.port=9090
2 환경 변수 SERVER_PORT=9090
3 SPRING_APPLICATION_JSON JSON 형식 환경 변수
4 프로파일별 yml application-prod.yml
5 기본 application.yml 기본 설정

높은 우선순위가 낮은 것을 덮어쓴다. 개발은 application.yml, 운영은 환경 변수나 명령행 인자로 오버라이드한다. 이 구조가 12-factor app의 "환경별 설정 분리" 원칙을 구현한다.

비유: 회사에서 "정장 입고 와"라는 지시가 있다고 하자. 전사 공지(yml)로 정장이 기본이다. 하지만 팀장(프로파일)이 "우리 팀은 캐주얼이야"라고 바꾸면 — 팀장 말이 우선이다. 그런데 CEO(환경 변수)가 "오늘은 전원 운동복이야"라고 하면 — CEO 말이 최종이다. Spring Boot 프로퍼티도 이렇게 계층이 있다.

@ConfigurationProperties — 타입 안전 프로퍼티

// Spring Boot 4 / Java 25 — 커스텀 프로퍼티
@ConfigurationProperties(prefix = "app")
public record AppProperties(
    String name,
    int maxConnections,
    PaymentConfig payment,
    List<String> allowedOrigins
) {
    public record PaymentConfig(String apiKey, boolean sandbox) {}
}

// application.yml
# app:
#   name: my-service
#   max-connections: 100
#   payment:
#     api-key: sk_test_12345
#     sandbox: true
#   allowed-origins:
#     - https://app.example.com
#     - https://admin.example.com
// Spring Boot 4 / Java 25 — 사용
@Service
public class PaymentService {
    private final AppProperties.PaymentConfig paymentConfig;

    public PaymentService(AppProperties props) {
        this.paymentConfig = props.payment();
    }
}

@ConfigurationProperties는 record와 결합하여 불변 + 타입 안전한 프로퍼티 바인딩을 제공한다. @Value("${app.name}")보다 컴파일 타임 안전성과 IDE 자동 완성이 우수하다. 장 09에서 더 자세히 풀어간다.

프로파일 — 환경별 설정

# application.yml (공통)
spring:
  profiles:
    active: dev   # 기본 활성 프로파일

---
# application-dev.yml 없이도 프로파일을 한 파일에 정의 가능
spring:
  config:
    activate:
      on-profile: dev

server:
  port: 8080

logging:
  level:
    com.example: DEBUG

---
spring:
  config:
    activate:
      on-profile: prod

server:
  port: 80

logging:
  level:
    com.example: WARN

---로 YAML 문서를 분리하면 하나의 파일에 여러 프로파일을 정의할 수 있다. 프로파일 전환: --spring.profiles.active=prod 또는 환경 변수 SPRING_PROFILES_ACTIVE=prod.

Spring Boot 4.0 — 모듈화된 Starter

Spring Boot 4.0은 코드베이스 전체 모듈화를 수행했다:

Spring Boot 3 Spring Boot 4
spring-boot-autoconfigure (거대 단일 jar) 기능별 모듈 분리 (spring-boot-web, spring-boot-data-jpa 등)
모든 자동 구성이 하나의 jar 필요한 모듈만 로드
큰 클래스패스 작은 클래스패스, 빠른 시작

모듈화의 실익: GraalVM native image 빌드 시 분석 대상이 줄어들어 빌드 시간과 이미지 크기가 감소한다. 불필요한 자동 구성이 로드되지 않아 시작 시간도 단축된다.

실습 — Starter와 프로퍼티 패턴

// Spring Boot 4 / Java 25 — ConfigDemo.java
// Spring 없이 프로퍼티 계층 시뮬레이션
import java.util.*;

public class ConfigDemo {
    public static void main(String[] args) {
        // 프로퍼티 소스 계층 (낮은 것이 우선)
        Map<String, String> defaults = Map.of("server.port", "8080", "db.url", "localhost");
        Map<String, String> profile = new HashMap<>(defaults);
        profile.put("db.url", "prod-db:5432");   // 프로파일 오버라이드
        Map<String, String> env = new HashMap<>(profile);
        env.put("server.port", "9090");   // 환경 변수 오버라이드

        System.out.println("server.port: " + env.get("server.port"));   // 9090 (env)
        System.out.println("db.url: " + env.get("db.url"));             // prod-db:5432 (profile)
    }
}
java ConfigDemo.java
server.port: 9090
db.url: prod-db:5432

확인할 것: 환경 변수가 프로파일 설정을 덮어쓰고, 프로파일이 기본값을 덮어쓴다. Spring Boot가 17개 이상의 프로퍼티 소스를 이 계층 구조로 관리한다.

@Value vs @ConfigurationProperties — 선택 기준

// 간단한 단일 값: @Value
@Value("${app.name}")
private String appName;

// 복잡한 구조화된 설정: @ConfigurationProperties
@ConfigurationProperties(prefix = "app")
public record AppProperties(String name, int maxConnections, List<String> origins) {}
기준 @Value @ConfigurationProperties
단일 값 OK overkill
중첩 구조 어려움 OK (record)
List/Map 어려움 OK
타입 안전성 낮음 (String) 높음 (컴파일 타임)
검증 어려움 @Validated로 검증
IDE 자동 완성 제한적 풍부

단일 값은 @Value, 구조화된 설정은 @ConfigurationProperties. 프로덕션에서는 @ConfigurationProperties를 기본으로 한다 — 타입 안전성과 검증이 장점이다.

요약 — 이 글의 결론

  • Starter는 의존성 버전 호환성을 큐레이션한다. 한 줄로 Spring MVC + Tomcat + Jackson 등 필요한 모든 라이브러리를 호환되는 버전으로 가져온다.
  • application.yml로 설정을 외부화한다. 코드와 설정을 분리하여 환경별 배포를 지원한다. 프로퍼티 소스 계층(명령행 > 환경변수 > 프로파일 yml > 기본 yml)이 우선순위를 결정한다.
  • @ConfigurationProperties로 타입 안전 바인딩을 한다. record와 결합하여 불변 + 컴파일 타임 검증 + IDE 자동 완성.
  • 프로파일로 환경을 분리한다. spring.profiles.active로 dev/staging/prod 전환. 한 파일에 ---로 다중 프로파일 정의 가능.
  • Spring Boot 4.0은 모듈화된 구조다. 더 작은 JAR, 더 빠른 시작, GraalVM AOT 친화적.

생각해 볼 문제

  1. spring-boot-starter-webspring-boot-starter-webflux를 동시에 의존성에 넣으면 어떤 일이 일어나는가?
  2. @ConfigurationProperties record에 기본값을 주려면 어떻게 하는가? Java record의 특성상 필드 기본값이 불가능한 제약은?
  3. Spring Boot 4.0 모듈화가 기존 Spring Boot 3 애플리케이션의 마이그레이션에 미치는 영향은?
  4. 환경 변수 SPRING_DATASOURCE_URLapplication.ymlspring.datasource.url에 매핑되는 규칙은?
  5. application.ymlapplication.properties를 같이 쓰면 어떤 것이 우선인가?

참고

Spring Boot 4.0 — 구조화된 로깅 설정

# Spring Boot 4 / Java 25 — application.yml
logging:
  structured:
    format:
      console: ecs   # Elastic Common Schema JSON
      file: gelf     # Graylog 형식 (파일)
  file:
    name: /var/log/myapp/app.log
  logback:
    rollingpolicy:
      max-file-size: 10MB
      max-history: 30

구조화된 로깅은 JSON 형식으로 로그를 출력하여 ELK, Datadog 등에서 검색/필터링을 용이하게 한다. ecs(Elastic Common Schema)와 gelf(Graylog)를 기본 지원한다. (Spring Boot 4.0 - Structured Logging)

프로퍼티 우선순위 실전 시나리오

# 개발: application-dev.yml의 설정이 적용됨
java -jar app.jar --spring.profiles.active=dev

# 운영: 환경 변수가 application-prod.yml을 덮어씀
DB_URL=jdbc:postgresql://prod-db:5432/myapp SPRING_PROFILES_ACTIVE=prod java -jar app.jar

# 긴급: 명령행 인자가 환경 변수를 덮어씀
java -jar app.jar --server.port=9090 --spring.profiles.active=prod

Spring Boot 4.0 — 모듈화된 Starter의 영향

Spring Boot 4.0의 모듈화는 Starter에도 영향을 미친다:

  • 각 기능이 별도 모듈로 분리되어 필요한 것만 로드
  • GraalVM native image 빌드 시 분석 범위 감소 → 빌드 시간 단축
  • 커스텀 Starter를 만들 때도 모듈 단위로 분리 권장
  1. Spring Boot 4.0과 이전 버전(Spring Boot 3.x)의 가장 큰 차이점은 무엇인가? 마이그레이션 시 주의할 점은?
  2. 이 글에서 다룬 개념을 실제 프로젝트에 적용할 때 가장 먼저 고려해야 할 것은?

'Develop Artifacts > Spring Boot' 카테고리의 다른 글

SpringBoot - 06. testing  (0) 2026.07.12
SpringBoot - 05. spring-data-jpa  (0) 2026.07.12
SpringBoot - 4. rest api  (0) 2026.07.12
SpringBoot - 03. embedded-server  (0) 2026.07.12
SpringBoot - 01. auto configuration  (0) 2026.07.12