--- title: "Spring Boot Exit Code Mechanism — ExitCodeGenerator, ExitCodeExceptionMapper, startup failure path" source_type: official-doc url: https://docs.spring.io/spring-boot/reference/features/spring-application.html#features.spring-application.application-exit archive_url: related_branches: [feature-migration-startup-contract] related_projects: [ca-skeleton] tags: [spring-boot, exit-code, startup-failure, ExitCodeGenerator, ExitCodeExceptionMapper] created: 2026-06-09 --- # Spring Boot Exit Code Mechanism — ExitCodeGenerator, ExitCodeExceptionMapper, startup failure path > Layer: `raw/official-docs/` — Spring Boot 공식 참조 문서 + spring-boot-3.4.0-sources.jar 직독. ## Parent / 활용 branch (필수) | Branch | 이 자료가 정당화하는 결정 | |---|---| | [[raw/branch-notes/feature-migration-startup-contract]] | D7: startup exit code 표준(78/70/71/72)의 Spring Boot 측 메커니즘 — ExitCodeExceptionMapper가 context refresh 실패 시 실제로 호출되는지, 기본 exit code가 무엇인지 | ## 출처 / Source - 원본 URL: https://docs.spring.io/spring-boot/reference/features/spring-application.html#features.spring-application.application-exit - ExitCodeExceptionMapper javadoc: https://docs.spring.io/spring-boot/api/java/org/springframework/boot/ExitCodeExceptionMapper.html - 소스코드 직독: spring-boot-3.4.0-sources.jar, `org/springframework/boot/SpringApplication.java` (로컬 Gradle 캐시: `/home/donghyeon/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot/3.4.0/`) - 저자 / 조직: Phillip Webb, Dave Syer (Spring Boot 핵심 기여자) - 마지막 확인일: 2026-06-09 ## 왜 저장했는지 / Why archived D7 결정(startup exit code = 78/70/71/72)을 구현할 때 Spring Boot가 제공하는 exit code 메커니즘이 실제로 startup failure 시 작동하는지 확인하기 위해 수집. ExitCodeExceptionMapper가 context refresh 실패 시점에 호출 가능한지가 핵심 질문. ## 핵심 인용 / Key quotes (verbatim) > [§Application Exit] "In addition, beans may implement the `ExitCodeGenerator` interface if they wish to return a specific exit code when `SpringApplication.exit()` is called. This exit code can then be passed to `System.exit()` to return it as a status code." > [§Application Exit] "Also, the `ExitCodeGenerator` interface may be implemented by exceptions. When such an exception is encountered, Spring Boot returns the exit code provided by the implemented `getExitCode()` method." > [§Application Exit] "If there is more than one `ExitCodeGenerator`, the first non-zero exit code that is generated is used. To control the order in which the generators are called, additionally implement the `Ordered` interface or use the `@Order` annotation." > [SpringApplication.java:896-899, source] `private int getExitCodeFromMappedException(ConfigurableApplicationContext context, Throwable exception) { if (context == null || !context.isActive()) { return 0; } ... }` > [SpringApplication.java:1412, source] `exitCode = (exitCode != 0) ? exitCode : 1;` ## Claims Extracted / 추출된 주장 | Claim ID | Claim (이 자료가 직접 말하는 것) | Evidence quote | Strength | Applies to | Does not prove | |---|---|---|---|---|---| | SB-EXIT-C1 | ExitCodeGenerator interface를 implements한 bean은 `SpringApplication.exit()` 호출 시 지정한 exit code를 반환한다 | [§Application Exit] "beans may implement the `ExitCodeGenerator` interface if they wish to return a specific exit code when `SpringApplication.exit()` is called" | `official-vendor-doc` | Spring Boot 1.0+ 모든 버전 | `SpringApplication.exit()`가 호출되어야 작동함. main()에서 `System.exit(SpringApplication.exit(...))` 패턴이 없으면 이 경로가 실행되지 않는다 | | SB-EXIT-C2 | 예외 클래스 자체가 ExitCodeGenerator를 구현하면, 그 예외가 발생할 때 해당 exit code가 반환된다 | [§Application Exit] "the `ExitCodeGenerator` interface may be implemented by exceptions. When such an exception is encountered, Spring Boot returns the exit code provided by the implemented `getExitCode()` method" | `official-vendor-doc` | Spring Boot 3.x startup exception chain 내 어떤 위치에서든 작동 (context 의존 없음) | ExitCodeExceptionMapper와 달리 context active 상태 불필요 — 단, 예외 클래스를 직접 수정 가능해야 함 | | SB-EXIT-C3 | ExitCodeExceptionMapper는 `context == null` 또는 `!context.isActive()` 이면 조회되지 않는다 (exit code 0 반환) | [SpringApplication.java:896-899] `if (context == null \|\| !context.isActive()) { return 0; }` | `official-vendor-doc` (소스코드 직독) | Spring Boot 3.4.0. context refresh 실패(BeanCreationException 등)는 isActive()=false에 해당함 | ExitCodeExceptionMapper bean이 등록된 경우라도, env 누락처럼 context 생성 이전 실패에는 해당 bean이 조회되지 않음을 증명 | | SB-EXIT-C4 | startup 실패 시 exit code 결정 순서: (1) ExitCodeExceptionMapper (context active 필요), (2) 예외의 ExitCodeGenerator 구현, (3) 둘 다 0이면 최종 fallback = 1 | [SpringApplication.java:888-893, 1412] `getExitCodeFromMappedException` → `getExitCodeFromExitCodeGeneratorException` → `exitCode = (exitCode != 0) ? exitCode : 1` | `official-vendor-doc` (소스코드 직독) | Spring Boot 3.4.0 startup failure path (handleRunFailure → handleExitCode → getExitCodeFromException) | 이 순서는 Spring Boot 버전마다 다를 수 있음. 3.4.0 소스 직독 기준. | | SB-EXIT-C5 | SpringBootExceptionHandler가 UncaughtExceptionHandler로 등록되어 있어, 커스텀 exit code가 실제로 JVM System.exit()로 전파된다 | [SpringBootExceptionHandler.java:49,63] `void registerExitCode(int exitCode) { this.exitCode = exitCode; }` + `if (this.exitCode != 0) { System.exit(this.exitCode); }` | `official-vendor-doc` (소스코드 직독) | Spring Boot 3.4.0 main thread uncaughtException path | 커스텀 exit code가 등록되어야 이 경로가 실행됨. 등록이 0이면 System.exit()가 호출되지 않고 예외가 전파됨 | | SB-EXIT-C6 | Spring Boot 공식 문서는 특정 숫자 exit code (78, 70, 71, 72)를 권장하거나 정의하지 않는다 | [§Application Exit] 예시 코드: `return () -> 42;` — 숫자 선택은 애플리케이션 구현자의 책임 | `official-vendor-doc` | 모든 Spring Boot 버전 | 어떤 숫자를 exit code로 사용해야 하는지는 공식이 규정하지 않음 — sysexits(3) 같은 외부 컨벤션을 따르는 것은 구현자 결정 | ## Usage Boundaries / 적용 경계 - 이 자료가 직접 증명하는 것: - `SB-EXIT-C3`: ExitCodeExceptionMapper bean은 context refresh 실패 시 호출되지 않음 (context.isActive() = false 조건) - `SB-EXIT-C2`: 예외 클래스 자체가 ExitCodeGenerator를 구현하면 context 상태 무관하게 exit code 적용됨 - `SB-EXIT-C4`: 커스텀 exit code 없을 때 기본 fallback = 1 - `SB-EXIT-C5`: SpringBootExceptionHandler를 통해 JVM 실제 exit code로 전파됨 - 이 자료가 증명하지 않는 것: - 어떤 숫자를 exit code로 사용해야 하는지 (78, 70, 71, 72 등) — Spring Boot는 숫자 규약을 정의하지 않음 (SB-EXIT-C6) - Kubernetes가 이 exit code를 어떻게 처리하는지 - ExitCodeExceptionMapper bean이 migration failure처럼 context active 상태에서 발생하는 실패에 작동하는지 — 소스 분석에 따르면 작동하지만 ca-tmpl integration test 검증 필요 - 내 프로젝트에 적용하려면 추가 확인이 필요한 것: - env 누락 실패가 실제로 context == null 또는 !isActive() 경로를 타는지 ca-tmpl에서 직접 확인 - migration failure(Flyway ApplicationRunner)에서 ExitCodeExceptionMapper vs ExitCodeGenerator 중 어느 것이 더 신뢰할 수 있는지 테스트 ## 메모 / Notes - ExitCodeExceptionMapper는 graceful shutdown (`SpringApplication.exit()` 호출)과 ApplicationRunner 실패 시 잘 작동하지만, env 누락처럼 context 생성 이전 실패에는 ExitCodeGenerator 구현이 유일한 방법. - Spring Boot가 exit code 숫자 규약을 정의하지 않으므로, 78/70/71/72는 sysexits(3) BSD 컨벤션을 따르는 ca-tmpl 내부 결정임. ## Related / 관련 - [[raw/official-docs/sysexits-bsd-exit-code-convention]] — BSD sysexits(3) 컨벤션 (EX_CONFIG=78, EX_SOFTWARE=70 등) - [[raw/branch-notes/feature-migration-startup-contract]] — D7 결정 (UNSUPPORTED_DECISION 라벨 해소 대상)