본문 바로가기

스타터와 의존성 관리

Boot 스타터와 의존성 관리의 역할을 익히고 버전 재정의·서버 교체·중복 의존성을 검증합니다.

스타터는 소스 코드를 대신 만들어 주지 않습니다. 특정 기능을 시작하는 데 필요한 의존성 묶음을 제공할 뿐이고, 의존성 관리(dependency management)가 그 그래프의 버전을 검증된 조합으로 맞춥니다.

그래서 애플리케이션의 build.gradle에서 줄 수가 줄었다는 것보다, 팀이 어떤 기능을 골랐고 버전 호환성을 누가 확인하는지가 더 중요합니다. 이 글에서는 스타터의 의존성 그래프와 BOM의 버전 정렬, 서버·로깅 구현의 교체, 개발용과 운영용 의존성의 범위, 공급망 검증을 차례로 살펴봅니다.

의존성 선언은 정렬·해석·패키징·실행 증거로 끝난다

starter 선택·BOM 규칙·해결 그래프·실행 패키징으로 확인할 산출물이 단계마다 바뀐다.

DEPENDENCIES · ALIGN AND PACKAGE

버전 정렬과 실행 아카이브 패키징은 다른 책임이다

스타터 좌표를 선언한 뒤 BOM 또는 관리 규칙으로 버전을 정렬합니다. 도구가 해결한 실제 그래프를 확인하고 Boot 플러그인으로 실행 산출물을 만듭니다.

선택·버전관리·해결·패키징의 책임스타터선택→BOM/관리규칙→실제해결그래프→실행패키징을확인하는교육용의존흐름이다. Gradle은dependency-management plugin 또는nativeBOM을연결해야하며Boot패키징플러그인만으로모든좌표를관리하지않는다. 화살표는책임간입력의전달이고각기능의실제구동성공은이후별도검증한다. 원4노드3관계를mobile같은의미로유지한다.
Starter 선언필요 기능 선택
연결 관계Starter 선언 · 필요 기능 선택 → BOM · 관리 규칙 · 호환 버전 제약
BOM · 관리 규칙호환 버전 제약
연결 관계BOM · 관리 규칙 · 호환 버전 제약 → 해결된 그래프 · 충돌·제외·범위
해결된 그래프충돌·제외·범위
연결 관계해결된 그래프 · 충돌·제외·범위 → Boot 패키징 · 실행 아카이브
Boot 패키징실행 아카이브
스타터 선언, BOM 정렬, 실제 그래프, 실행 패키징네 단계는 스타터 선언, BOM 버전 정렬, 실제 의존성 그래프 해석, Boot plugin 실행 아카이브 패키징이다. 별도 실행 증거가 이후에 필요하다.Starter 선언기능 의존성 묶음BOM · 관리호환 버전 정렬해결된 그래프충돌 · 제외 · scopeBoot plugin실행 패키징선언 파일 → 실제 classpath → 실행 산출물의 동작을 각각 확인
  1. Starter → BOM/관리 → 해결된 그래프 → 패키징

    버전 관리와 실행 아카이브 생성은 별도 책임입니다. 충돌·제외·scope가 반영된 결과를 확인합니다.

버전과 구현 · 변경 근거

직접 버전 재정의에는 호환성 근거와 만료 조건을 둡니다. 서버/로깅 구현 교체는 기존 기본값을 제외하고 실제 활성 구현이 하나인지 확인합니다.

패키징 뒤 실제 실행

JAR 엔트리·중첩 라이브러리와 실행 결과를 봅니다. 웹 서비스는 실제 HTTP와 종료까지, 콘솔 예제는 출력·종료 코드까지 확인합니다.

컴파일 성공·클래스 존재·빈 활성화·실제 요청 동작은 서로 다른 증거입니다. 잠금·체크섬과 해결된 그래프도 릴리스 산출물에 연결합니다.

이 예의 조건

  • 두 박스는 같은 실행의 진행 정보와 자료·결과를 관찰하는 고정 역할입니다. 박스의 좌우·위아래 위치를 별도 호출 순서로 해석하지 않습니다.
  • 조건별 종료는 대안입니다. 실패 뒤 정상 후속 단계를 실행하거나 독립 비교 사례를 같은 요청으로 연결하지 않습니다.
  • 스타터 선택→BOM/관리 규칙→실제 해결 그래프→실행 패키징을 확인하는 교육용 의존 흐름이다. Gradle은 dependency-management plugin 또는 native BOM을 연결해야 하며 Boot 패키징 플러그인만으로 모든 좌표를 관리하지 않는다. 화살표는 책임 간 입력의 전달이고 각 기능의 실제 구동 성공은 이후 별도 검증한다. 원래 4노드와 3관계를 세로 도표에서도 같은 의미로 유지한다.
  • 네 단계는 스타터 선언, BOM 버전 정렬, 실제 의존성 그래프 해석, Boot plugin 실행 아카이브 패키징이다. 별도 실행 증거가 이후에 필요하다.
관계도의 보충 설명
원래 전체 그림의 표시 문구·조건·주석
순번원문 표시
1의존성 선언은 정렬·해석·패키징·실행 증거로 끝난다
5선택·버전 관리·해결·패키징의 책임
6스타터 선택→BOM/관리 규칙→실제 해결 그래프→실행 패키징을 확인하는 교육용 의존 흐름이다. Gradle은 dependency-management plugin 또는 native BOM을 연결해야 하며 Boot 패키징 플러그인만으로 모든 좌표를 관리하지 않는다. 화살표는 책임 간 입력의 전달이고 각 기능의 실제 구동 성공은 이후 별도 검증한다. 원래 4노드와 3관계를 세로 도표에서도 같은 의미로 유지한다.
단계별 상태·값과 전환 이유
장면관찰 값전환 이유
starter·관리 규칙

starter를 선택하고 BOM 또는 관리 규칙을 연결합니다.

입력: starter · Gradle: BOM 연결 필요선언 좌표의 관리 근거가 준비됩니다.
실제 해결 그래프

의존성 해결 결과를 확인합니다.

산출물: 해결 그래프 · Boot plugin: 모든 좌표 관리 아님선언과 실제 선택 버전을 비교합니다.
실행 패키징 증거

해결 그래프에서 실행 패키징을 확인합니다.

산출물: 실행 패키지 · 기능 성공: 별도 검증실행 입력이 준비되며 기능 증거는 별도로 남습니다.

의존성 선언은 정렬·해석·패키징·실행 증거로 끝난다

starter 선택·BOM 규칙·해결 그래프·실행 패키징으로 확인할 산출물이 단계마다 바뀐다.

DEPENDENCIES · ALIGN AND PACKAGE

버전 정렬과 실행 아카이브 패키징은 다른 책임이다

스타터 좌표를 선언한 뒤 BOM 또는 관리 규칙으로 버전을 정렬합니다. 도구가 해결한 실제 그래프를 확인하고 Boot 플러그인으로 실행 산출물을 만듭니다.

선택·버전관리·해결·패키징의 책임스타터선택→BOM/관리규칙→실제해결그래프→실행패키징을확인하는교육용의존흐름이다. Gradle은dependency-management plugin 또는nativeBOM을연결해야하며Boot패키징플러그인만으로모든좌표를관리하지않는다. 화살표는책임간입력의전달이고각기능의실제구동성공은이후별도검증한다. 원4노드3관계를mobile같은의미로유지한다.
Starter 선언필요 기능 선택
연결 관계Starter 선언 · 필요 기능 선택 → BOM · 관리 규칙 · 호환 버전 제약
BOM · 관리 규칙호환 버전 제약
연결 관계BOM · 관리 규칙 · 호환 버전 제약 → 해결된 그래프 · 충돌·제외·범위
해결된 그래프충돌·제외·범위
연결 관계해결된 그래프 · 충돌·제외·범위 → Boot 패키징 · 실행 아카이브
Boot 패키징실행 아카이브
스타터 선언, BOM 정렬, 실제 그래프, 실행 패키징네 단계는 스타터 선언, BOM 버전 정렬, 실제 의존성 그래프 해석, Boot plugin 실행 아카이브 패키징이다. 별도 실행 증거가 이후에 필요하다.Starter 선언기능 의존성 묶음BOM · 관리호환 버전 정렬해결된 그래프충돌 · 제외 · scopeBoot plugin실행 패키징선언 파일 → 실제 classpath → 실행 산출물의 동작을 각각 확인
  1. Starter → BOM/관리 → 해결된 그래프 → 패키징

    버전 관리와 실행 아카이브 생성은 별도 책임입니다. 충돌·제외·scope가 반영된 결과를 확인합니다.

버전과 구현 · 변경 근거

직접 버전 재정의에는 호환성 근거와 만료 조건을 둡니다. 서버/로깅 구현 교체는 기존 기본값을 제외하고 실제 활성 구현이 하나인지 확인합니다.

패키징 뒤 실제 실행

JAR 엔트리·중첩 라이브러리와 실행 결과를 봅니다. 웹 서비스는 실제 HTTP와 종료까지, 콘솔 예제는 출력·종료 코드까지 확인합니다.

컴파일 성공·클래스 존재·빈 활성화·실제 요청 동작은 서로 다른 증거입니다. 잠금·체크섬과 해결된 그래프도 릴리스 산출물에 연결합니다.

이 예의 조건

  • 두 박스는 같은 실행의 진행 정보와 자료·결과를 관찰하는 고정 역할입니다. 박스의 좌우·위아래 위치를 별도 호출 순서로 해석하지 않습니다.
  • 조건별 종료는 대안입니다. 실패 뒤 정상 후속 단계를 실행하거나 독립 비교 사례를 같은 요청으로 연결하지 않습니다.
  • 스타터 선택→BOM/관리 규칙→실제 해결 그래프→실행 패키징을 확인하는 교육용 의존 흐름이다. Gradle은 dependency-management plugin 또는 native BOM을 연결해야 하며 Boot 패키징 플러그인만으로 모든 좌표를 관리하지 않는다. 화살표는 책임 간 입력의 전달이고 각 기능의 실제 구동 성공은 이후 별도 검증한다. 원래 4노드와 3관계를 세로 도표에서도 같은 의미로 유지한다.
  • 네 단계는 스타터 선언, BOM 버전 정렬, 실제 의존성 그래프 해석, Boot plugin 실행 아카이브 패키징이다. 별도 실행 증거가 이후에 필요하다.

관계도의 보충 설명

원래 전체 그림의 표시 문구·조건·주석
순번원문 표시
1의존성 선언은 정렬·해석·패키징·실행 증거로 끝난다
5선택·버전 관리·해결·패키징의 책임
6스타터 선택→BOM/관리 규칙→실제 해결 그래프→실행 패키징을 확인하는 교육용 의존 흐름이다. Gradle은 dependency-management plugin 또는 native BOM을 연결해야 하며 Boot 패키징 플러그인만으로 모든 좌표를 관리하지 않는다. 화살표는 책임 간 입력의 전달이고 각 기능의 실제 구동 성공은 이후 별도 검증한다. 원래 4노드와 3관계를 세로 도표에서도 같은 의미로 유지한다.
단계별 상태·값과 전환 이유
장면관찰 값전환 이유
starter·관리 규칙

starter를 선택하고 BOM 또는 관리 규칙을 연결합니다.

입력: starter · Gradle: BOM 연결 필요선언 좌표의 관리 근거가 준비됩니다.
실제 해결 그래프

의존성 해결 결과를 확인합니다.

산출물: 해결 그래프 · Boot plugin: 모든 좌표 관리 아님선언과 실제 선택 버전을 비교합니다.
실행 패키징 증거

해결 그래프에서 실행 패키징을 확인합니다.

산출물: 실행 패키지 · 기능 성공: 별도 검증실행 입력이 준비되며 기능 증거는 별도로 남습니다.

그림은 필요한 기능에 맞는 스타터를 선언하고, BOM이나 관리 규칙으로 호환되는 버전을 정한 뒤, 충돌·제외·범위가 반영된 실제 해결 그래프를 확인하고, Boot 플러그인으로 실행 아카이브를 만드는 네 단계입니다. 화살표는 각 단계의 결과가 다음 단계의 입력이 된다는 뜻이며, Boot 패키징 플러그인만으로 모든 좌표의 버전이 관리되지는 않습니다. 아래 칸들은 버전 재정의와 구현 교체에 남길 이유, 그리고 패키징한 뒤 실제 실행으로 확인해야 할 항목을 정리합니다.


스타터의 의존성 그래프

Web MVC, Spring Data JPA, Actuator 스타터는 각각 MVC, JPA 영속성, 운영 엔드포인트 기능을 묶습니다. 스타터 하나를 추가하면 로깅, 검증, JSON처럼 이미 다른 스타터가 가져온 의존성이 중복된 경로로 다시 나타날 수 있지만, Gradle의 의존성 해결은 그중 하나의 버전을 고릅니다.

src/main/java/board/deps/Capability.java
package board.deps;

import java.util.Set;

public record Capability(String name, Set<String> requiredModules) {
    public Capability {
        if (name.isBlank() || requiredModules.isEmpty()) {
            throw new IllegalArgumentException("capability needs modules");
        }
        requiredModules = Set.copyOf(requiredModules);
    }

    public static void main(String[] args) {
        var web = new Capability("webmvc", Set.of("mvc", "json", "server"));
        System.out.printf("capability=%s modules=%d%n",
                web.name(), web.requiredModules().size());
    }
}

이 레코드는 기능 하나가 어떤 모듈을 필요로 하는지 기록하는 모델이며, 실행하면 capability=webmvc modules=3을 출력합니다. 스타터를 넣었지만 쓰지 않는 모듈은 컴파일 클래스 경로와 공격 표면만 늘립니다. 의존성 분석과 런타임의 자동 구성 보고서를 함께 보고 제거합니다.

더 깊이: Spring Boot 4의 모듈 분리가 스타터에 남긴 것

Spring Boot 4.0부터 스타터 아래의 구조가 달라졌습니다. 4.0 마이그레이션 안내서에 따르면 Boot는 여러 개의 큰 JAR 대신 작고 초점이 분명한 모듈을 내놓으며, 모듈은 spring-boot-<기술>, 스타터는 spring-boot-starter-<기술>이라는 이름 규칙을 따릅니다. 예전에는 spring-boot-autoconfigure 한 JAR이 거의 모든 기술의 자동 구성을 담았지만, 이제는 Spring MVC의 자동 구성이 spring-boot-webmvc 모듈에 들어 있는 식으로 기술마다 나뉩니다. 8장의 서블릿 오류 디스패치에서 Boot 4의 ErrorController가 org.springframework.boot.webmvc 아래에 있었던 것도 이 분리의 결과입니다.

그래서 예전 이름의 스타터는 남아 있지만 사용 중단 예정입니다. Spring Boot 4.1.2의 spring-boot-starter-web은 설명에 spring-boot-starter-webmvc로 대체되었다고 적혀 있고, 안내서는 이런 예전 스타터가 앞으로의 릴리스에서 제거될 것이라고 밝힙니다. 테스트 지원도 기술별로 나뉘어, 자체 테스트 인프라가 있는 기술은 spring-boot-starter-<기술>-test로 바꾸라고 안내합니다. 이전 세대와 비슷한 구성으로 일단 옮기고 싶다면 모든 모듈을 담되 그 전이 의존성은 빼는 spring-boot-starter-classic과 spring-boot-starter-test-classic이 있지만, 안내서는 결국 이 클래식 스타터에서도 벗어나라고 권합니다.


Boot BOM의 버전 관리

Boot의 BOM을 가져오면 Spring Framework, Jackson, Tomcat, Hibernate 같은 연관 라이브러리의 버전이 한 집합으로 정렬됩니다. 그중 한 라이브러리만 무리하게 올리면 바이너리 메서드 시그니처가 달라져, 시작할 때 연결 오류가 날 수 있습니다.

관리되는 버전을 재정의할 때는 공식 지원 범위, 이유, 만료 날짜, 의존성 분석 결과, 통합 테스트를 기록합니다. 보안 패치가 필요하다면 먼저 Boot의 패치 릴리스로 전체 버전 집합을 함께 올릴 수 있는지 검토합니다. 직접 의존성에 버전을 적지 않았다는 것은 최신 버전을 아무거나 쓴다는 뜻이 아니라, 가져온 플랫폼이 버전을 정한다는 뜻입니다.

Gradle에서는 Boot 플러그인이 맡는 실행 JAR 패키징과 버전 관리를 나눠서 봅니다. Gradle 플러그인의 의존성 관리 문서는 io.spring.dependency-management 플러그인으로 Boot BOM을 가져오는 방법과 Gradle의 기본 BOM 지원을 쓰는 방법, 두 가지를 설명합니다. 이 교재의 누적 프로젝트는 Java 25와 Spring Boot에서 정한 대로 platform('org.springframework.boot:spring-boot-dependencies:4.1.2')을 쓰는 뒤쪽 방법입니다. org.springframework.boot 플러그인을 선언한 것만으로 관리 밖 좌표의 버전까지 정해지지는 않으므로, 실제 build.gradle에 어떤 BOM이 적용됐는지 먼저 찾고 해결된 결과와 대조합니다. 해결된 의존성 그래프는 릴리스 산출물과 함께 보관합니다.


서버와 로깅 구현 교체

Tomcat 대신 다른 내장 서버를 쓰려면 새 서버 스타터를 추가하는 것만으로는 부족하고, 기본 서버 의존성을 제외해야 합니다. 로깅 백엔드도 브리지가 서로를 부르는 순환이나 두 구현이 함께 있는 상태를 피합니다. 컴파일에 성공한 뒤에는 실제 서버 팩토리와 로거 바인딩이 하나씩인지 확인합니다.

src/main/java/board/deps/RuntimeCapabilityProbe.java
package board.deps;

public final class RuntimeCapabilityProbe {
    static boolean present(String className) {
        try {
            Class.forName(className, false,
                    RuntimeCapabilityProbe.class.getClassLoader());
            return true;
        } catch (ClassNotFoundException missing) {
            return false;
        }
    }

    public static void main(String[] args) {
        boolean tomcat = present("org.apache.catalina.startup.Tomcat");
        boolean springMvc = present("org.springframework.web.servlet.DispatcherServlet");
        System.out.printf("mvc=%s tomcat=%s%n", springMvc, tomcat);
    }
}

이 코드는 Class.forName에 initialize=false를 넘겨 두 클래스가 클래스 경로에 있는지만 조회합니다. 기본 Web MVC 환경에서 확인할 항목을 함께 적으면 다음과 같습니다.

기본 Web MVC 실행 환경 관찰
mvc=true tomcat=true
serverFactories=1
loggingProviders=1
linkageErrors=0

이 코드가 직접 출력하는 것은 첫 줄뿐입니다. 뒤의 세 줄은 서버 팩토리, 로깅 공급자, 연결 오류를 별도의 통합 검사로 확인할 항목을 적은 예시입니다. 클래스가 있다는 것만으로 그 빈이 활성화됐다고 판단하지 않으며, 조건 평가 보고서와 웹 서버의 시작까지 확인합니다.

의존성 그래프에서 같은 모듈이 여러 경로로 보이는 것과, 런타임에 구현이 실제로 두 개 있는 것은 다른 문제입니다. 같은 모듈을 여러 스타터가 참조했다면 하나의 해결된 버전으로 모일 수 있지만, 서로 다른 서버 구현의 모듈이 둘 남았다면 어느 쪽이 선택되는 조건인지와 제외하려던 의도를 읽어야 합니다.

version alignment 오류 신호
Spring Framework resolved version = 7.0.x
manually overridden integration version = incompatible line
compile = success
context refresh = failure
root cause = NoSuchMethodError
result = MANAGED_VERSION_SET_BROKEN

이 실패는 의존성이 빠진 경우와 다릅니다. 클래스는 있지만, 컴파일할 때 기대한 메서드와 런타임의 바이트코드가 어긋난 것입니다. dependencyInsight 작업으로 누가 그 버전을 골랐는지 확인하고, 제외를 마구 더하기 전에 Boot 플랫폼이 정한 버전으로 되돌립니다.


개발용과 운영용 의존성

테스트 컨테이너, 개발용 재시작 도구, 애노테이션 처리기가 런타임 이미지에 들어가지 않도록 구성의 범위(configuration)를 확인합니다. 데이터베이스 드라이버는 런타임에는 필요하지만 컴파일 단계에서 그 API를 직접 쓰지 않는다면 runtimeOnly가 알맞을 수 있습니다.

선택적인 기능을 스타터 하나에 모두 넣으면, 사용자는 쓰지 않는 SDK까지 받게 됩니다. 자체 스타터를 만든다면 핵심 API, 자동 구성, 선택적 통합을 모듈로 나누고 클래스 경로 조건을 씁니다. 라이선스, 플랫폼 아키텍처, 네이티브 라이브러리 포함 여부도 그래프를 검토할 때 함께 봅니다. 전이 의존성이라 몰랐다는 사정이 운영에서 생긴 문제를 덜어 주지는 않습니다.


공급망 잠금과 검증

버전 잠금(dependency locking)은 동적 버전 해결로 생기는 차이를 막고, 체크섬 검증은 산출물이 바뀐 것을 감지합니다. 잠금 파일을 갱신하는 PR에서는 이전과 새 그래프, 보안 취약점, 크기, 기본 구동 확인 결과를 함께 봅니다.

저장소 미러의 주소와 인증 정보를 빌드 스크립트에 직접 적지 않습니다. 의존성 혼동(dependency confusion) 공격을 막도록, 승인된 저장소와 그룹별 저장소 정책을 씁니다.


업그레이드 검증 단계

자바 컴파일, 컨텍스트 로딩, 실제 HTTP·JPA 동작, 실행 JAR의 구동 확인을 단계별로 실행합니다. 사용 중단 예정 API의 제거와 속성 이름 변경은 마이그레이션 안내서를 따라 고치고, 이전 버전과의 호환 계층을 언제 걷어 낼지도 정합니다.

의존성을 바꾸는 PR에는 해결된 의존성 그래프의 이전과 이후, 추가·제거된 JAR의 크기, 자동 구성에서 조건이 맞은 항목의 차이, 시작과 첫 요청의 지연 시간을 첨부합니다. 버전 숫자가 최신이라는 사실만으로 호환성이나 효율이 확인되지는 않습니다. 급하게 넣은 재정의에는 담당자와 만료 날짜를 지정하고, 다음 Boot 패치 릴리스에서 제거되는지 확인합니다.


정리

  • 스타터는 기능별 의존성 묶음이고, BOM은 그 그래프의 버전을 검증된 조합으로 맞춥니다.
  • Boot 플러그인은 실행 JAR 패키징을 맡으며, 버전 관리는 io.spring.dependency-management 플러그인이나 Gradle의 platform으로 따로 적용합니다.
  • 서버나 로깅 구현을 바꿀 때는 기본 구현을 제외하고, 실제로 활성화된 구현이 하나인지 시작과 요청으로 확인합니다.
  • 테스트·개발·처리기 의존성은 알맞은 구성 범위에 두고, 잠금과 체크섬, 해결된 그래프를 릴리스와 함께 남깁니다.

연습 문제

1. 회원 게시판의 의존성 그래프

Web MVC와 Actuator만 필요한 회원 게시판 서비스의 의존성 그래프를 설계하세요. 서버 교체, 테스트 범위의 H2, 운영용 드라이버, 애노테이션 처리기, 쓰지 않는 JPA의 제거, 잠금 파일 갱신의 이유를 표로 작성하세요.

해설 보기

기능마다 담당자와 범위를 정하면, 스타터를 추가한 이유와 각 의존성의 쓰임이 분명해집니다. 결정 하나를 다음과 같은 값으로 남길 수 있습니다.

package board.deps;

public record DependencyDecision(
        String coordinate,
        String capability,
        Scope scope,
        String owner
) {
    public enum Scope { COMPILE, RUNTIME, TEST, PROCESSOR }

    public DependencyDecision {
        if (coordinate.isBlank() || capability.isBlank() || owner.isBlank()) {
            throw new IllegalArgumentException("dependency decision incomplete");
        }
    }
}

정기 감사에서는 소스 코드에서 쓰이지 않는 직접 의존성과, 런타임 클래스 경로에만 남아 있는 오래된 모듈을 제거 후보로 제시합니다.

2. 범위 결정과 서버 교체 판정

서비스는 Web MVC와 Actuator만 필요하고 DB 영속성은 쓰지 않습니다. 테스트에서만 H2의 JDBC 드라이버로 별도 검사를 하며, 운영 이미지에는 넣지 않습니다. JPA 스타터, H2, 애노테이션 처리기의 역할과 범위를 정하세요. 새 서버로 바꾼 뒤 RuntimeCapabilityProbe의 첫 줄 mvc=true tomcat=true만 얻었다면, 서버 교체가 성공했다고 판정할 수 있나요?

해설 보기

쓰지 않는 JPA 스타터는 제거 후보이고, DB가 없는 이 조건에서는 운영용 드라이버도 필요하지 않습니다. H2의 API를 직접 참조하지 않는 별도의 JDBC 테스트라면 testRuntimeOnly 같은 테스트 실행 범위를, 애노테이션 처리기는 annotationProcessor 같은 전용 범위를 씁니다.

서버 교체는 기본 구현의 제외와, 실제로 선택된 팩토리, 시작, HTTP 응답, 종료까지 확인해야 하므로 클래스 존재를 나타내는 두 값으로 판정하지 않습니다. 오히려 tomcat=true는 기본 서버를 아직 제외하지 않았을 가능성을 알려 줍니다. 요구가 바뀌어 DB 영속성이 필요해지면 운영용 드라이버와 관련 구성을 새로 추가합니다.

3. 제외를 잊은 서버 교체

다른 서버 스타터를 추가하면서 기본 Tomcat 의존성의 제외를 잊었습니다. RuntimeCapabilityProbe의 출력은 어떻게 되나요? 어느 서버가 실제로 포트를 열었는지는 무엇으로 확인해야 하나요?

해설 보기

Tomcat 클래스가 여전히 클래스 경로에 있으므로 출력은 그대로 mvc=true tomcat=true입니다. 이 검사는 클래스가 있는지만 보므로, 두 서버 구현이 함께 남은 상태와 교체가 끝난 상태를 구별하지 못합니다.

어느 서버 팩토리가 선택되는지는 자동 구성의 조건과 순서에 달려 있으므로, 조건 평가 보고서와 시작 로그에서 실제로 만들어진 서버 팩토리와 포트를 연 서버를 확인합니다. 그다음 기본 서버를 제외하고, 해결된 의존성 그래프에서 서버 구현이 하나만 남았는지 다시 봅니다.

다음 글 자동 구성 과정에서는 이렇게 고른 의존성을 보고 Boot가 어떤 순서로 자동 구성 후보를 읽고 조건을 평가해 빈을 등록하는지 따라갑니다.