RE:개발자

Spring Boot 실행 버튼을 누르면 실제로 무슨 일이 일어날까? | RE:개발자 #4

nocklock 2026. 9. 17. 10:26

Spring Boot, 실행 버튼을 누르면무슨 일이 일어날까?

개발하면서 정말 많이 눌렀던 버튼이 있다.

IntelliJ의 초록색 실행 버튼.

 
public static void main(String[] args) {
    SpringApplication.run(SecurityLensApplication.class, args);
}
 

회사에서도 수도 없이 봤던 코드다.

SpringApplication.run().

이걸 실행하면 서버가 켜지고,

브라우저에서 localhost:8080으로 접속하면 내가 만든 화면이 나온다.

예전에는 사실 여기까지만 알았다.

“Spring Boot 실행하는 코드.”

그런데 Gradle을 다시 공부하다 보니 또 궁금해졌다.

실행 버튼을 누른 뒤에 대체 무슨 일이 일어나는 걸까?


시작은 결국 Java main()이다

Spring Boot 프로젝트도 결국 Java 프로그램이다.

그래서 시작점은 특별하지 않다.

 
public static void main(String[] args)
 

Java를 처음 배울 때 봤던 바로 그 main() 메서드다.

차이가 있다면 그 안에서

 
SpringApplication.run(...)
 

을 실행한다는 것이다.

나는 예전에는 이 한 줄을 거의 주문처럼 생각했다.

 
SpringApplication.run();
 

적으면 Spring이 실행된다.

틀린 말은 아니지만,

이번에는 그 뒤에서 어떤 일이 일어나는지 조금 더 들여다봤다.


1. SpringApplication.run()이 실행된다

 
SpringApplication.run(SecurityLensApplication.class, args);
 

여기서 Spring Boot가 애플리케이션 실행을 시작한다.

설정 정보를 읽고,

현재 애플리케이션이 어떤 형태인지 판단하고,

Spring이 관리할 환경을 준비한다.

그리고 중요한 것이 하나 만들어진다.

바로 ApplicationContext다.


2. ApplicationContext가 만들어진다

Spring을 공부하면 굉장히 자주 등장하는 단어다.

ApplicationContext
 

예전에는 이것도 그냥

“Spring 컨테이너.”

정도로 외웠다.

지금 다시 이해해보면,

Spring이 객체들을 생성하고 관리하기 위한 공간이라고 생각하면 편했다.

예를 들어 우리가 이런 클래스를 만든다.

 
@Service
public class ImageAnalysisService {

}
 

일반 Java라면 필요할 때 직접 객체를 만들어야 한다.

 
ImageAnalysisService service
        = new ImageAnalysisService();
 

그런데 Spring에서는 보통 직접 이렇게 만들지 않는다.

Spring이 객체를 생성하고 관리한다.

그 객체를 우리가 흔히 Bean이라고 부른다.

즉,

ApplicationContext
        ↓
Spring Bean 관리
        ↓
Controller
Service
Repository
...
 

이런 구조라고 이해했다.


3. @SpringBootApplication을 찾는다

Spring Boot 프로젝트의 메인 클래스를 보면 보통 이런 코드가 있다.

 
@SpringBootApplication
public class SecurityLensApplication {

    public static void main(String[] args) {
        SpringApplication.run(
                SecurityLensApplication.class,
                args
        );
    }
}
 

여기서 중요한 것이

 
@SpringBootApplication
 

이다.

예전에는 그냥

“Spring Boot 프로젝트니까 붙이는 어노테이션.”

정도로 생각했다.

그런데 실제로는 여러 역할을 합쳐놓은 어노테이션이다.

대표적으로

@Configuration
@EnableAutoConfiguration
@ComponentScan
 

의 기능이 포함되어 있다.

이 중 내가 먼저 이해해야겠다고 생각한 건 ComponentScan이었다.


4. Spring이 내 클래스를 찾아다닌다

내 프로젝트에는 이런 것들이 있다.

 
@RestController
@Service
@Repository
@Component
 

Spring은 Component Scan을 통해 이런 클래스들을 찾아서 관리 대상으로 등록한다.

예를 들어

 
@RestController
public class AnalysisController {

}
 

그리고

 
@Service
public class ImageAnalysisService {

}
 

가 있다면,

Spring이 해당 클래스들을 발견하고 객체를 생성한다.

결국 우리가 매번

 
new AnalysisController();
new ImageAnalysisService();
 

를 하지 않아도 되는 이유 중 하나다.

그리고 여기서 예전에 외웠던 단어가 다시 등장한다.

IoC.


IoC를 이제야 조금 이해했다

면접 공부를 하면 이런 질문을 많이 본다.

IoC가 뭔가요?

예전의 나는 이렇게 외웠다.

제어의 역전입니다.

맞는 말이다.

그런데 사실 그 뒤를 설명하기가 애매했다.

지금은 이렇게 이해하고 있다.

일반 Java 프로그램에서는 내가 객체를 만든다.

 
ImageAnalysisService service
        = new ImageAnalysisService();
 

즉 객체 생성에 대한 제어권이 나에게 있다.

Spring에서는 객체 생성을 Spring에게 맡긴다.

 
@Service
public class ImageAnalysisService {
}
 

그러면 Spring이 객체를 생성하고 관리한다.

객체를 만들고 관리하는 제어권이 개발자에게서 Spring으로 넘어간 것.

그래서 Inversion of Control, 제어의 역전이라고 부르는 것이다.

단어만 외웠을 때보다 훨씬 이해가 됐다.


5. Auto Configuration이 동작한다

Spring Boot가 편한 가장 큰 이유 중 하나다.

자동 설정.

예를 들어 내가

 
implementation 'org.springframework.boot:spring-boot-starter-web'
 

을 추가하면

Spring Boot는

웹 프로젝트를 만들려고 하는구나.

라고 판단하고 필요한 설정들을 자동으로 구성한다.

과거 Spring에서는 개발자가 직접 설정해야 했던 많은 부분을 Spring Boot가 대신 처리해준다.

여기서 3편에서 공부했던 Gradle과 연결된다.

build.gradle
      ↓
starter-web 추가
      ↓
관련 라이브러리 로딩
      ↓
Spring Boot Auto Configuration
      ↓
웹 애플리케이션 환경 구성
 

Gradle과 Spring Boot가 완전히 따로 노는 것이 아니었다.

조금씩 연결되기 시작했다.


6. 내장 웹 서버가 실행된다

그리고 Spring Boot 웹 프로젝트라면 서버도 필요하다.

예전 Spring MVC 프로젝트에서는 Tomcat을 별도로 설치해서 사용하는 경우가 많았다.

나 역시 회사에서 Tomcat 설정을 직접 만졌던 기억이 있다.

그런데 Spring Boot에서는 기본적으로 웹 서버를 애플리케이션 안에 포함해서 사용할 수 있다.

대표적으로 Tomcat이다.

그래서 프로젝트를 실행하면 콘솔에 이런 메시지가 보인다.

Tomcat started on port 8080
 

그동안 별 생각 없이 지나쳤던 로그다.

하지만 이 시점에서야 비로소

localhost:8080
 

으로 요청을 받을 준비가 된 것이다.


그런데 요청은 Controller로 바로 가는 걸까?

여기서 또 하나 궁금해졌다.

브라우저에서

GET /api/analyze
 

같은 요청을 보내면 바로 Controller가 실행되는 걸까?

정확히는 아니다.

Spring MVC에는 요청을 먼저 받아주는 중요한 객체가 있다.

바로

DispatcherServlet이다.


7. DispatcherServlet이 요청을 받는다

Spring MVC 구조에서 DispatcherServlet은 굉장히 중요한 역할을 한다.

웹 요청이 들어오면 먼저 DispatcherServlet이 요청을 받고,

어떤 Controller가 처리해야 하는지 찾아간다.

예를 들어

 
@RestController
@RequestMapping("/api")
public class AnalysisController {

    @PostMapping("/analyze")
    public AnalysisResponse analyze() {

    }
}
 

가 있다면,

POST /api/analyze
 

요청이 들어왔을 때 적절한 Controller 메서드를 찾아 연결해준다.

간단하게 보면 이런 흐름이다.

Browser
   ↓
Tomcat
   ↓
DispatcherServlet
   ↓
Controller
   ↓
Service
   ↓
Repository
 

그리고 결과는 반대 방향으로 돌아간다.

Repository
   ↓
Service
   ↓
Controller
   ↓
HTTP Response
   ↓
Browser
 

내가 회사에서 만들었던 MVC 구조도 결국 이 흐름 위에서 동작하고 있었다.


결국 실행 버튼 하나 뒤에 이렇게 많은 일이 있었다

처음에는 그냥

▶ Run
 

이었다.

그런데 조금만 안쪽을 들여다보니 대략 이런 흐름이었다.

main()
  ↓
SpringApplication.run()
  ↓
ApplicationContext 생성
  ↓
Component Scan
  ↓
Bean 생성 및 관리
  ↓
Auto Configuration
  ↓
내장 Tomcat 실행
  ↓
DispatcherServlet 준비
  ↓
HTTP 요청 처리
 

물론 실제 Spring Boot 내부는 이것보다 훨씬 복잡하다.

그래도 적어도 이제는

“Spring Boot가 어떻게 실행되나요?”

라는 질문에

SpringApplication.run()이라고만 대답하고 끝내지는 않을 수 있을 것 같다.


이번에도 Claude Code에게 물어봤다

요즘 프로젝트를 만들면서 Claude Code를 같이 사용하고 있다.

이번에는 단순히

Spring Boot 실행 과정 알려줘.

라고 묻는 데서 끝내지 않았다.

내가 만든 프로젝트에서

현재 프로젝트를 기준으로 Spring Boot 실행 이후 어떤 Bean들이 만들어지고 Controller 요청까지 어떤 구조로 연결되는지 설명해줘.

처럼 실제 프로젝트를 기준으로 물어봤다.

그랬더니 책에서 보는 추상적인 설명보다 훨씬 이해하기 쉬웠다.

내 Controller, Service, DTO가 실제 설명 속에 등장하기 때문이다.

AI를 공부에 사용하는 방법도 조금씩 바뀌고 있다.

답을 대신 얻는 도구에서, 내가 작성한 코드를 이해하는 도구로.

이 방식이 지금의 나에게는 꽤 잘 맞는다.


예전에 외웠던 단어들이 연결되기 시작했다

이번에 Spring Boot 실행 과정을 다시 보면서 재미있는 점이 있었다.

예전에 따로따로 외웠던 단어들이 하나의 흐름으로 연결되기 시작했다.

Gradle
Dependency
Spring Boot
Bean
ApplicationContext
IoC
Component Scan
Tomcat
DispatcherServlet
MVC
 

회사에서는 전부 사용했던 것들이다.

그런데 당시에는 각각을 따로 알고 있었다.

지금 다시 공부하면서 느끼는 건,

개발 공부에서 중요한 건 용어를 얼마나 많이 아느냐가 아니라

그 기술들이 어떻게 연결되어 있는지를 이해하는 것인지도 모르겠다.


RE:개발자

한 번 개발자였던 사람이
다시 개발자가 되어가는 과정을 기록합니다.

이번에는 실행 버튼 하나를 조금 깊게 들여다봤다.

그리고 다음에는 그 실행된 서버에

http://localhost:8080
 

으로 요청을 보냈을 때,

HTTP 요청이 실제로 어떻게 Controller까지 도착하는지

조금 더 자세히 따라가보려고 한다.