스타터와 의존성 관리
Boot 스타터와 의존성 관리의 역할을 익히고 버전 재정의·서버 교체·중복 의존성을 검증합니다.
스타터는 소스 코드를 대신 생성하지 않고 특정 기능을 시작하는 의존성 묶음을 제공합니다.
의존성 관리는 그 그래프의 버전을 검증된 조합으로 맞춥니다.
애플리케이션 build.gradle에서 줄 수가 줄어드는 것보다, 팀이 어떤 기능을 선택했고 누가 버전 호환성을 책임지는지가 중요합니다.
의존성 선언은 정렬·해석·패키징·실행 증거로 끝난다
starter 선택·BOM 규칙·해결 그래프·실행 패키징으로 확인할 산출물이 단계마다 바뀐다.
DEPENDENCIES · ALIGN AND PACKAGE
버전 정렬과 실행 아카이브 패키징은 다른 책임이다
스타터 좌표를 선언한 뒤 BOM 또는 관리 규칙으로 버전을 정렬합니다. 도구가 해결한 실제 그래프를 확인하고 Boot 플러그인으로 실행 산출물을 만듭니다.
- 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 플러그인으로 실행 산출물을 만듭니다.
- 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: 모든 좌표 관리 아님 | 선언과 실제 선택 버전을 비교합니다. |
| 실행 패키징 증거 해결 그래프에서 실행 패키징을 확인합니다. | 산출물: 실행 패키지 · 기능 성공: 별도 검증 | 실행 입력이 준비되며 기능 증거는 별도로 남습니다. |
스타터 의존성 그래프
Web MVC, Spring Data JPA, Actuator 스타터는 각각 MVC, JPA 영속성, 운영 엔드포인트 기능을 묶습니다.
하나를 추가하면 로깅, 검증, JSON처럼 이미 다른 스타터가 가져온 의존성이 중복 경로로 나타날 수 있지만 Gradle의 의존성 해결 과정은 하나의 버전을 선택합니다.
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());
}
}스타터를 넣었는데 사용하지 않는 모듈은 컴파일 클래스 경로와 공격 표면을 늘립니다.
의존성 분석과 런타임 자동 구성 보고서를 함께 보고 제거합니다.
Boot BOM 버전 관리
플러그인 또는 플랫폼을 사용하면 Spring 프레임워크, Jackson, Tomcat, Hibernate 같은 연관 라이브러리 버전이 정렬됩니다.
한 라이브러리만 무리하게 올리면 바이너리 메서드 시그니처가 달라져 시작 시 연결 오류가 날 수 있습니다.
관리 버전을 재정의할 때는 공식 지원 범위와 이유, 만료 날짜, 의존성 분석 결과, 통합 테스트를 기록합니다.
보안 패치가 필요하면 가능한 Boot 패치 릴리스로 전체 버전 집합을 올리는 방법을 먼저 검토합니다.
직접 의존성 버전이 없다는 것은 “최신 아무거나”가 아니라 가져온 플랫폼이 결정한다는 뜻입니다.
Gradle에서는 Boot 플러그인의 실행 JAR 패키징과 버전 관리를 나누어 확인합니다. 공식 의존성 관리는 io.spring.dependency-management 플러그인을 적용해 Boot BOM을 가져오거나 Gradle의 native BOM 지원을 쓰는 두 경로를 설명합니다. org.springframework.boot 플러그인 이름만 선언했다고 관리 밖 좌표의 버전까지 자동 결정되는 것은 아닙니다. 실제 build.gradle에서 어느 BOM·구성이 적용됐는지 먼저 찾고 resolved 결과를 대조하세요.
해결된 의존성 그래프를 릴리스 산출물과 함께 보존합니다.
서버·로깅 구현 교체
Tomcat 대신 다른 내장 서버를 쓰려면 새 스타터만 추가하지 않고 기존 기본값 서버 의존성을 제외합니다.
로깅 백엔드도 브리지 순환과 두 구현을 피합니다.
컴파일 성공 뒤 실제 서버 팩토리와 로거 바인딩이 하나인지 확인합니다.
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);
}
}mvc=true tomcat=true
serverFactories=1
loggingProviders=1
linkageErrors=0위 코드의 직접 출력은 첫 줄뿐입니다. 뒤 세 줄은 서버 팩토리·로깅 공급자·링키지 오류를 별도 통합 검사로 확인할 항목을 적은 예시이며, 클래스 존재만으로 빈 활성화를 증명하지 않습니다.
조건 보고서와 웹 서버 시작을 추가로 확인합니다.
예시 RuntimeCapabilityProbe는 initialize=false로 클래스 존재를 조회합니다. mvc=true·tomcat=true는 그 두 이름을 로더가 찾았다는 첫 출력입니다. 새 서버 스타터를 추가한 뒤 두 서버 구현의 클래스가 모두 남아도 이 존재 검사는 참일 수 있습니다. 어느 서버 팩토리 빈이 실제 활성화됐고 포트를 누가 열었는지는 별도 증거입니다.
의존성 그래프의 중복 경로와 실제 런타임 구현 두 개도 다릅니다. 같은 모듈을 여러 스타터가 참조한 경우 하나의 해결된 버전으로 모일 수 있고, 서로 다른 서버 구현의 모듈이 둘 남은 경우에는 선택 조건과 제외 의도를 읽어야 합니다.
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 플랫폼으로 되돌립니다.
개발·운영 의존성
테스트 컨테이너, 개발용 재시작 도구, 애노테이션 처리기가 런타임 이미지에 들어가지 않게 구성 스코프를 확인합니다.
데이터베이스 드라이버는 실제 런타임에서 필요하지만 컴파일 API를 직접 쓰지 않으면 runtimeOnly가 적합할 수 있습니다.
선택적 기능을 스타터 하나에 모두 넣으면 사용자가 사용하지 않는 SDK를 받습니다.
자체 스타터는 핵심 API, 자동 구성, 선택적 통합을 모듈로 나누고 조건부 클래스 경로를 사용합니다.
라이선스와 플랫폼 아키텍처, 네이티브 라이브러리 여부도 그래프 검토 대상입니다.
“전이 의존성이라 몰랐다”는 운영 환경 책임을 없애지 않습니다.
공급망 잠금·검증
버전 잠금은 동적 해결 차이를 막고 체크섬 검증은 산출물 바뀜을 감지합니다.
잠금 파일 갱신 PR은 이전·신규 그래프, CVE, 크기, 기본 구동 검증 결과를 함께 봅니다.
리포지토리 미러와 인증 정보를 빌드 스크립트에 하드 코딩하지 않습니다.
의존성 혼동 공격을 막도록 승인된 리포지토리와 그룹 정책을 사용합니다.
업그레이드 검증 계층
Java 컴파일, 컨텍스트 로딩, 실제 HTTP·JPA 동작, 실행 가능한 JAR 파일의 구동 검증을 단계별로 실행합니다.
사용 중단 예정 API 제거와 속성 이름 변경은 마이그레이션 안내서를 따라 수정하고 이전 호환 계층의 제거 시점을 정합니다.
의존성 변경 PR에는 해결된 의존성 그래프의 이전·이후, 추가·제거 JAR 크기, 자동 구성 긍정 일치 차이, 시작과 첫 요청 지연 시간을 첨부합니다.
버전 숫자만 최신이라는 사실은 호환성이나 효율을 증명하지 않습니다.
긴급 재정의에는 담당자와 만료 날짜를 지정하고 다음 Boot 패치 릴리스에서 제거되는지 확인합니다.
연습 문제
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");
}
}
}정기 감사에서는 소스 코드에서 사용되지 않는 직접 의존성과 런타임 클래스 경로에만 남은 구식 모듈을 제거 후보로 제시합니다.
독립 확인: 서비스는 Web MVC·Actuator만 필요하고 DB 영속성은 사용하지 않습니다. 테스트에서만 H2의 JDBC 드라이버로 별도 검사를 하며 운영 이미지에는 넣지 않습니다. JPA 스타터·H2·애노테이션 처리기의 역할과 범위를 결정하세요. 새 서버로 바꾼 뒤 mvc=true·tomcat=true라는 Probe 첫 줄만 얻었다면 서버 교체 성공으로 판정할 수 있나요?
풀이 확인
미사용 JPA 스타터는 제거 후보이고 운영 드라이버도 DB가 없는 이 조건에서는 필수 기능이 아닙니다. H2를 직접 API로 참조하지 않는 별도 JDBC 테스트라면 testRuntimeOnly 같은 테스트 실행 범위, 처리기는 annotationProcessor 같은 전용 범위를 사용합니다. 서버 교체는 기존 기본 구현 제외와 실제 선택된 팩토리·시작·HTTP·종료 증거까지 확인해야 하므로 클래스 존재 두 값으로 성공 판정하지 않습니다. DB 영속성이 필요한 요구로 바뀌면 운영 드라이버와 관련 구성을 새로 추가해야 합니다.