안녕하세요.

우리는 IntelliJ에서 초록색 화살표 버튼을 누르거나, 터미널에서 java -jar 명령어를 입력하면 수 초 내에 서버가 뜨는 것을 당연하게 여깁니다. 콘솔창에 화려하게 나타나는 Spring 로고와 수많은 로그 메시지들… 과연 그 짧은 찰나에 스프링 부트 내부에서는 어떤 일이 벌어지고 있는 걸까요?
이 과정을 이해하는 것은 단순히 지식을 넓히는 것을 넘어, 배포 환경에서 발생하는 복잡한 오류를 해결하고 애플리케이션 성능을 최적화하는 데 큰 도움이 됩니다. 오늘은 스프링 부트가 실행되는 5가지 핵심 단계를 통해 그 마법 같은 과정을 속 시원히 파헤쳐 보겠습니다.
1. 메인 메서드의 실행과 SpringApplication 클래스
모든 시작은 자바의 표준 진입점인 public static void main 메서드입니다. 여기서 호출되는 SpringApplication.run() 메서드가 거대한 스프링 부트 엔진의 시동을 거는 역할을 합니다.
이 단계에서 스프링 부트는 가장 먼저 애플리케이션의 타입을 결정합니다. 현재 프로젝트가 서블릿 기반의 웹 앱인지, 리액티브 웹 앱인지, 아니면 일반 자바 앱인지 판단하여 그에 맞는 ApplicationContext를 준비합니다.
2. SpringApplicationRunListeners와 환경 설정
시동이 걸리면 스프링 부트는 미리 등록된 리스너들을 깨워 “이제 실행 시작한다!”라고 알립니다. 그런 다음 Environment(환경)를 구성합니다.
application.properties나application.yml파일을 읽습니다.- 시스템 환경 변수나 커맨드 라인 인자들을 수집합니다.
- 이 정보들을 합쳐서 하나의 설정 정보로 통합합니다.
3. ApplicationContext 생성 및 빈(Bean) 스캔
이제 핵심 객체들을 담을 바구니인 ApplicationContext를 실제로 생성합니다. 이때 스프링의 ‘마법’인 Component Scan이 일어납니다.
메인 클래스에 붙은 @SpringBootApplication 어노테이션 덕분에, 스프링은 해당 패키지 하위의 모든 클래스를 훑으며 @Component, @Service, @Repository, @Controller 등이 붙은 클래스들을 찾아 자바 객체(Bean)로 만듭니다. 이 과정에서 객체 간의 의존 관계를 파악하고 주입(DI)하는 작업이 정교하게 수행됩니다.
4. 내장 서블릿 컨테이너(Tomcat) 구동
일반적인 스프링 프레임워크와 가장 차별화되는 지점입니다. 객체 준비가 어느 정도 끝나면, 스프링 부트는 내부에 포함된 Embedded Tomcat을 깨웁니다.
별도의 설치된 서버 없이도 웹 서비스가 가능한 이유가 바로 이것입니다. 스프링 부트는 ApplicationContext 안에서 톰캣을 직접 초기화하고 구동하며, 우리가 작성한 컨트롤러들을 톰캣의 서블릿 포트에 매핑합니다.
5. CommandLineRunner와 ApplicationRunner 실행
서버까지 완벽하게 떴다면, 마지막으로 사용자가 “앱 시작 직후에 꼭 실행해 줘”라고 요청한 로직들을 처리합니다. CommandLineRunner 인터페이스를 구현한 빈이 있다면, 이 시점에 run() 메서드가 호출됩니다. 주로 초기 데이터를 DB에 넣거나 환경 설정을 검증하는 용도로 사용됩니다.
핵심 코드 분석: 실행 과정을 제어하는 도구들
코드 예제 1: 시작 시 로직 실행 (CommandLineRunner)
애플리케이션이 구동된 직후에 특정 코드를 실행하고 싶을 때 사용합니다.
@Component
public class MyInitializer implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println(">>>>> 서버가 성공적으로 가동되었습니다. 초기 작업을 수행합니다.");
// 예: 초기 관리자 계정 생성 로직
}
}
코드 예제 2: 커스텀 배너 설정하기
스프링 부트가 시작될 때 뜨는 로고를 바꿀 수 있습니다. src/main/resources/banner.txt 파일을 만들면 됩니다.
____ _ ____
/ ___| ___ __| | ___ ___ __ _ _ __ ___ _ __
| | / _ \/ _` |/ _ \ / __|/ _` | '_ ` _ \| '_ \
| |___ | __/ (_| | __/ | (__| (_| | | | | | | |_) |
\____| \___|\__,_|\___| \___|\__,_|_| |_| |_| .__/
|_|

결론
Spring Boot의 실행 과정은 ‘준비 – 구성 – 생성 – 구동 – 완료’라는 치밀한 단계로 이루어져 있습니다. @SpringBootApplication 어노테이션 하나가 이 복잡한 과정을 자동화해 주지만, 그 이면에서 동작하는 원리를 아는 개발자와 모르는 개발자의 역량 차이는 장애 발생 시 극명하게 드러납니다.
우리가 작성한 코드가 어떻게 살아 움직이는지 그 생명주기를 이해하는 것은 진정한 전문가로 거듭나는 첫걸음입니다. 이번 시리즈를 통해 Spring Boot와 조금 더 친해지셨기를 바랍니다.
지금까지 Spring Boot 입문 시리즈를 함께해 주셔서 감사합니다. 여러분의 코딩 인생에 Spring Boot가 든든한 조력자가 되길 응원하겠습니다!





