Tomcat은 그냥 서버가 아니다?

2025. 3. 23. 22:29·삽질로그

1. 들어가며

이전 글에서 Java의 ExecutorService와 Spring Boot의 TaskExecutor를 비교하며, Spring Boot의 비동기 요청 처리가 Tomcat의 스레드풀과 별개로 동작한다는 점을 정리했다. 

 

2025.03.16 - [삽질로그] - Spring Boot 비동기 처리 = 스레드풀?

 

Spring Boot 비동기 처리 = 스레드풀?

1. 들어가며이전 포스팅에서 Java의 ExecutorService와 Spring Boot의 스레드풀을 비교하는 방식이 잘못되었다는 피드백(토스 개발자 피셜)을 받았다. 2025.03.09 - [삽질로그] - 여러 요청이 동시에 들어오

mingking2.tistory.com

 

이번 글에서는 Spring Boot에서 가장 많이 사용되는 두 웹 기술인 Spring MVC(Tomcat 기반)와 Spring WebFlux(Netty 기반)의 구조적 차이를 소개하며,  

그중에서도 Spring MVC의 구조와 기반 기술인 Servlet, Tomcat의 작동 원리를 중심으로 깊이 있게 다뤄볼 예정이다.  
WebFlux와 Netty에 대한 내용은 다음 글에서 별도로 자세히 정리할 예정이다.

 


2. Spring? Spring Boot?

많은 개발자들이 “Spring Boot를 써서 개발해요”라고 말하지만, 그 안에 어떤 기술이 돌아가고 있는지는 모호하게 느껴질 수 있다. Spring과 Spring Boot는 서로 밀접하게 연결되어 있지만 그 역할과 목적은 분명히 다르다.

 

 

🌱 Spring Framework란?

Spring Framework는 자바 진영에서 가장 널리 사용되는 애플리케이션 프레임워크로, 애플리케이션을 구성하는 데 필요한 다양한 기능을 모듈화하여 제공한다.

 

기본적으로 POJO(Plain Old Java Object) 기반으로 설계되며, 개발자가 핵심 비즈니스 로직에 집중할 수 있도록

트랜잭션 처리, 메시징, 보안, 웹 개발, AOP 등 반복적이고 기술적인 작업들을 대신 처리해준다.

POJO : 특별한 상속이나 어노테이션 없이, 순수하게 필드와 메서드만으로 구성된 단순한 자바 객체

 

핵심 철학은 다음 두 가지로 요약된다:

  • IoC (Inversion of Control): 객체 생성과 의존성 주입을 프레임워크가 대신 처리
  • DI (Dependency Injection): 객체 간의 의존 관계를 외부에서 주입하여 느슨한 결합 유지

 

Spring Framwork 내부 구조도

🧩 Core Container

  • Core / Beans : 의존성 주입(DI), IoC 컨테이너의 중심. BeanFactory 및 설정 관련 기능
  • Context : ApplicationContext 제공, 국제화, 이벤트, 리소스 관리 등
  • SpEL : 런타임에서 객체를 다루는 표현식 (Spring Expression Language)

 

💾 Data Access / Integration

  • JDBC :반복 코드를 줄여주는 JDBC 템플릿 제공
  • ORM : JPA, Hibernate 등 통합 지원
  • OXM : 자바 객체 <-> XML 변환 지원
  • JMS : 메시징 기능 (Java Message Service)
  • Transcations : 선언적/프로그래밍 방식 트랜잭션 관리

 

🌐 Web 

  • Web / Servlet : Spring MVC의 기반, DispatcherServlet 포함
  • WebSocket : 양방향 통신 처리
  • Portlet : 포털 기반 앱 지원 (사용 빈도 낮음)

 

🎯 AOP 및 기타

  • AOP / Aspects : 로깅, 보안 같은 횡단 관심사를 분리
  • Instrumentation : 클래스 로딩 및 바이트코드 조작 (특정 WAS용)
  • Messaging : 메시징 연동을 위한 공통 추상화 계층

 

🧪 Test

  • Test : JUnit/TestNG 기반 테스트 환경, Mock 지원, ApplicationContext 로딩 지원

 

이러한 모듈을 조합하여 원하는 애플리케이션 구조를 설계할 수 있다. 하지만 초기 설정이 복잡하고 진입 장벽이 높다는 단점도 있다.

(XML 설정, 빈 등록, 의존성 충돌 등…)

 

🚀 Spring Boot란?

Spring Boot는 이러한 Spring의 복잡한 설정과 진입 장벽을 줄이고,

빠르게 실행 가능한 애플리케이션을 만들 수 있도록 도와주는 프로젝트이다.

 

“Spring을 쉽게 사용하도록 만들어주는 자동 구성 플랫폼”이라고 이해하면 된다.

 

핵심 목표는 다음과 같다:

  • 설정 자동화 (Auto Configuration) : 복잡한 XML/자바 기반 설정을 최소화
  • 내장 서버 지원 : Tomcat, Jetty, Netty 등을 애플리케이션에 내장 (별도 WAS 설치 불필요)
  • 독립 실행 구조 : main() 메서드로 쉽게 실행 가능 (Jar 패키징)
  • 운영 편의성 : 헬스 체크, 메트릭, 모니터링 기능을 기본 내장

즉, Spring Boot는 Spring을 쉽고 실용적으로 사용하는 실행 플랫폼이자 도구라고 볼 수 있다.

 

🤔 그럼 우리는 뭘 써야 하는가?

현대 대부분의 Spring 프로젝트는 Spring Boot 위에서 개발된다.

그리고 그 위에 실제로 동작하는 웹 프레임워크는 다음 두 가지 중 하나를 선택하게 된다:

  • Spring MVC: 전통적인 Servlet 기반 동기 방식
  • Spring WebFlux: Netty 기반의 비동기/논블로킹 방식

👉 이번 글에서는 이 중 Spring MVC를 중심으로, 그 기반이 되는 Servlet, Tomcat, Spring MVC의 내부 구조까지 깊이 있게 다뤄볼 예정이다.

Spring WebFlux는 다음 글에서 별도로 다루며, Netty의 이벤트 루프 구조, 동시성 처리 방식, 성능 특성을 집중적으로 비교해볼 계획이다.

 

Spring 전체 아키텍처나 모듈 구조에 대해 더 깊이 알고 싶다면 Spring 공식 문서를 참고하면 좋다.
https://docs.spring.io/spring-framework/docs/4.0.x/spring-framework-reference/html/overview.html
 

2. Introduction to Spring Framework

Spring Framework is a Java platform that provides comprehensive infrastructure support for developing Java applications. Spring handles the infrastructure so you can focus on your application. Spring enables you to build applications from "plain old Java o

docs.spring.io


3. 웹의 동적 처리, Servlet의 등장

위에서 설명한 것처럼 Spring MVC는 Servlet 기반이라고 하는데, 그럼 먼저 Servlet에 대해 알아보자

Servlet이란?

Servlet은 자바 기반의 웹 애플리케이션 프로그래밍 기술로, 서버 측에서 실행되어 클라이언트의 요청을 처리하고 동적인 웹 페이지를 생성하는 역할을 한다. 

Servlet이 왜 필요한가?

1️⃣ 정적 데이터만 전달하는 Web Server

정적 데이터(Home.html)를 전달

과거 웹이 처음 등장했을 때, 서버는 정적인 HTML 파일만을 제공했다. 하지만 사용자가 정보를 입력하거나, 검색하고, 주문하는 등의 동적인 요청을 처리하기 위해 서버 측 로직이 필요해졌다.

 

이때 처음 등장한 기술이 바로 CGI (Common Gateway Interface)이다.

 

2️⃣ 동적 데이터를 처리하는 CGI

CGI 구현체로 동적 데이터를 처리

CGI는 요청이 들어올 때마다 서버가 별도의 프로세스를 생성하여 외부 프로그램(C, PHP)을 실행하는 방식이다.

그렇다면 요청이 많이 들어온다면 어떻게 되는가?

 

요청마다 프로세스를 생성해서 처리

그림을 보면, 클라이언트의 요청이 들어올 때마다 웹 서버는 각 요청마다 새로운 프로세스를 생성하고, 해당 프로세스를 통해 별도의 CGI 구현체를 실행한다는 것을 알 수 있다.

 

이 구조는 단순하지만 치명적인 단점이 있다.

  1. 운영체제 수준에서 매 요청마다 새로운 프로세스를 생성해야 하므로 자원 소모가 매우 크고, 처리 속도도 느리다.
  2. 트래픽이 많아질수록 생성해야 할 프로세스 수도 급증하게 되고, 결국 시스템이 과부하에 쉽게 노출된다.
  3. 각 CGI 구현체가 별도의 프로세스로 동작하기 때문에, 메모리나 자원을 공유하지 못하고, 효율적인 상태 관리가 어렵다.

이러한 한계로 인해 CGI는 대규모 트래픽을 처리하는 현대 웹 환경에서는 부족하며, 이를 대체할 수 있는 기술로 서블릿(Servlet)이 등장하게 된다.

Servlet의 동작 원리

싱글톤 인스턴스 + 멀티스레드

Web Container에 요청이 들어오면 Thread를 생성하고 Servlet을 실행시킨다.

📌 서블릿 객체는 단 한 번만 생성 (SingleTon)

  • 서버 시작 시 한 번만 메모리에 로딩된다.
  • 모든 요청은 이 하나의 인스턴스를 공유한다.

📌 요청마다 새로운 스레드를 생성

  • 클라이언트 요청이 들어오면 별도의 스레드를 생성해 service() 메서드 실행
  • 따라서 동시에 여러 요청이 들어와도 서블릿 인스턴스 하나로 병렬 처리가 가능함 (Tomcat에서 설명)

이러한 구조 덕분에 서블릿은 자원을 효율적으로 사용하며 CGI보다 훨씬 빠른 성능을 보장할 수 있다.

 

Servlet 요청 처리 흐름

아래는 서블릿의 기본적인 처리 흐름이다:

  1. 클라이언트가 HTTP 요청 전송
  2. 웹 서버가 해당 요청을 서블릿 컨테이너(= Web Container)로 전달
  3. 서블릿 컨테이너가 해당 요청을 처리할 서블릿을 찾아 service() 메서드 호출
  4. 내부적으로 doGet(), doPost() 등 HTTP 메서드에 맞는 로직 실행
  5. 서블릿이 응답을 생성하여 클라이언트로 전송

Servlet 테스트

지금까지는 이론적으로 서블릿의 동작 방식을 살펴봤다. 이번엔 실제 테스트 코드를 통해 요청 처리 흐름을 직접 눈으로 확인해보자.

내부적으로 파고 들면 끝도 없기에 자세한 설명은 생략한다.

서블릿의 최상위 인터페이스인 Servlet의 정의이다. 이 인터페이스에는 생명주기와 관련된 주요 메서드들이 선언되어 있으며, 우리가 작성하는 서블릿은 이 메서드를 오버라이딩하여 구현하게 된다.

 

직접 코드를 작성하여 이 메서드들이 언제 호출되는지, 어떤 방식으로 요청을 처리하는지 테스트해보자.

 

테스트 코드

HttpServlet을 상속받아 서블릿 클래스를 만들고 @WebServlet으로 서블릿을 등록한다.
@Slf4j
@WebServlet(name = "HelloServlet", urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {

	public HelloServlet() { // 서블릿 객체가 최초 생성될 때 딱 한 번 실행
		log.info("HelloServlet 생성자 호출됨 (서블릿 객체 생성)");
	}

	@Override
	public void init() { // 서블릿이 생성된 후 한 번만 호출
		log.info("HelloServlet init() 호출됨 (서블릿 초기화)");
	}
    
    @Override
	public void service(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
		log.info("🔄 service() 호출됨 - 요청 메서드: {}", req.getMethod());
		super.service(req, resp);
	}

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
		log.info("doGet() 호출됨 - 처리 스레드: {}", Thread.currentThread().getName());

		String name = request.getParameter("name");
		response.setContentType("text/plain");
		response.setCharacterEncoding("UTF-8");
		response.getWriter().write("Hello, " + name);
	}
}

 

Spring Boot 애플리케이션에 위 서블릿을 직접 수동 등록해야 한다. 내장 톰캣의 서블릿 컨테이너에 등록하기 위해ServletRegistrationBean을 사용한다:
@SpringBootApplication
public class SpringTestApplication {

	...

	// 내장 톰캣에 서블릿 등록
	@Bean
	public ServletRegistrationBean<HelloServlet> helloServlet() {
		ServletRegistrationBean<HelloServlet> servletBean =
			new ServletRegistrationBean<>(new HelloServlet(), "/hello");
		return servletBean;
	}
}

 

테스트 실행 결과

 

📌 서버 실행 시점

  • Spring Boot 애플리케이션이 처음 실행되면, 서블릿 컨테이너가 HelloServlet 클래스를 로딩한다.
  • 이때 서블릿 객체는 단 한 번만 생성되며(싱글톤), 곧바로 init() 메서드가 호출되어 서블릿이 초기화된다.

 

📌 클라이언트 요청 시점

  • 사용자가 /hello?name=test와 같은 요청을 여러 번 보내면, 가장 먼저 service() 메서드가 호출된다.
  • service()는 HTTP 요청 방식에 따라 doGet(), doPost() 등 알맞은 메서드를 내부적으로 호출한다.
  • 이때 요청마다 서블릿 컨테이너가 새로운 스레드(http-nio-8080-exec-N)가 할당되어 동시에 병렬처리된다.

4. Tomcat은 서블릿을 어떻게 실행할까?

🤔 “톰캣이 요청을 처리한다” vs “서블릿 컨테이너가 요청을 처리한다”

지난 글에서 Spring Boot에서 여러 요청을 동시에 처리하는 역할은 Tomcat이 한다고 설명했다.

그런데 서블릿을 공부하다 보면 “요청은 서블릿 컨테이너가 처리한다”는 말도 등장한다.

 

그렇다면 도대체 어떤 말이 맞는 걸까?

 

결론부터 말하면, 두 표현 모두 맞는 말이다.

Tomcat은 대표적인 Servlet Container 구현체이기 때문이다.

 

즉, Tomcat이 서블릿 컨테이너 역할을 수행하는 구현체이기 때문에, 두 표현은 동일한 대상을 지칭하는 다른 표현일 뿐이다.

 

🤔  그렇다면, Tomcat은 정확히 무슨 일을 하는 걸까?

Tomcat은 단순한 Web Server가 아니라, HTTP 요청을 받아서 서블릿을 실행하고 응답을 반환하는 역할을 수행한다.

즉, 서블릿을 실행하는 주체이자, 생명주기를 관리하는 컨테이너인 것이다.

 

Servlet을 직접 실행하는 주체는 Tomcat이며, 이를 Servlet Container로 부른다.

 

Tomcat이란?

Tomcat은 Apache Software Foundation에서 개발한 오픈소스 웹 애플리케이션 서버(WAS)이다.

 

좀 더 구체적으로 설명하면,

 

“Java Servlet, JSP(Java Server Pages) 등 자바 웹 기술을 실행할 수 있게 해주는 서버”

즉, 자바 웹 어플리케이션을 구동하는 Servlet Container 역할을 수행한다.

 

Tomcat은 다음과 같은 기능을 제공한다:

역할 설명
HTTP 요청 수신 클라이언트로부터의 HTTP 요청을 수신
서블릿 매핑 URL에 따라 실행할 서블릿을 찾아 매핑
서블릿 생명주기 관리 서블릿 객체 생성 -> init() -> 요청마다 service() 호출 -> 종료 시 destroy()
HTTP 응답 반환 서블릿이 생성한 응답을 HTTP로 반환
동시 요청 처리 스레드풀을 사용해 요청을 병렬로 처리

 

 

Tomcat이 왜 필요한가?

1️⃣  자바로 웹을 만들기 위해 필요한 컨테이너

자바는 콘솔 프로그램이나 데스크탑 앱, 백엔드 시스템 개발에는 강력한 언어지만,

기본적으로 웹 요청(Request)과 응답(Response) 을 직접 처리할 수 있는 내장 기능은 없다.

 

웹 요청을 처리하려면 다음과 같은 기능이 필요하다:

  • HTTP 요청을 수신하고 파싱
  • 요청 URL에 따라 서블릿을 라우팅
  • 요청에 대한 응답을 HTTP 형식으로 작성 후 전송
  • 요청별로 적절한 스레드 처리

이러한 역할은 서블릿 컨테이너 또는 웹 서버가 담당해야 한다.

여기서 등장하는 것이 바로 Tomcat이다.

 

Tomcat은 HTTP 요청과 서블릿을 연결해주는 중간 매개체로,

자바와 웹을 연결해주는 브릿지 역할을 수행한다.

 

2️⃣ 동시 요청 처리 & 스레드풀 관리

Tomcat은 단순히 서블릿을 실행하는 것에 그치지 않고,

수많은 클라이언트의 요청을 동시에 처리할 수 있는 구조를 제공한다.

 

그 핵심이 바로 스레드풀(Thread Pool) 기반 아키텍처다.

스레드풀의 자세한 설명은 아래의 링크를 참고해주세요.

2025.03.09 - [삽질로그] - 여러 요청이 동시에 들어오면, Spring Boot는 어떻게 처리할까?

 

여러 요청이 동시에 들어오면, Spring Boot는 어떻게 처리할까?

1. 들어가며지난 글에서는 웹소켓 핸들러를 Event 기반으로 처리하여 동기 방식으로 해결했다.이를 통해 코드가 더 깔끔해지고 유지보수가 쉬워졌지만, 한 가지 새로운 고민이 생겼다. 🔗 이전

mingking2.tistory.com

 

 

Tomcat의 동작 원리

앞에서 직접 테스트한 서블릿 실행 흐름 (init(), service(), doGet())은 Tomcat이 Servlet Container로서 수행하는 동작의 핵심 흐름을 그대로 보여준 것이기 때문에 별도의 테스트를 생략했다.

로그를 살펴보면 Tomcat이 동작하고 있음을 알 수 있다.

 

Tomcat의 구조

대신 Tomcat이 어떤 구조로 이루어져 있는지 자세히 살펴보자

 

Tomcat의 구조는 크게 두 가지 축(Coyote, Catalina)로 나눌 수 있다.

 

구성 요소 역할
Coyote 클라이언트의 HTTP 요청을 수신하고, 내부적으로 Socket 연결 처리 및 Request/Response 객체 생성을 담당하는 입구 (Connector)
Catalina 실제로 서블릿을 실행하고 생명주기를 관리하는 내부 Servlet Container (init(), service(), destroy() 등 실행 주체)

 

🧱 Catalina 내부 구조: 서블릿 컨테이너 계층 구조

계층 구성 역할 설명
Connector - 클라이언트의 HTTP 요청을 수신 (Coyote)
- Socket 연결 관리 및 요청 파싱
- 요청을 ServletRequest 객체로 생성 후 Catalina에 전달
- Catalina가 처리한 응답을 다시 클라이언트에게 전달
Server - Tomcat 전체의 최상위 설정 단위
- 여러 Service를 포함하고 Tomcat의 전반적인 생명주기 관리
Service - 하나의 Connector와 하나의 Engine을 묶는 단위
- Connector로부터 요청을 받아 Engine에 전달하고, 응답을 다시 Connector로 전달
Engine - Catalina 내부의 핵심 실행 구조
- 모든 요청을 수신하여 적절한 Host로 라우팅
- 여러 Host 중에서 요청 도메인에 따라 Host 선택
Host - 하나의 도메인(예: localhost)에 해당
- 여러 Context(웹 애플리케이션)를 포함 가능
Context - 하나의 웹 애플리케이션(프로젝트)
- 실제로 우리가 작성한 Spring Boot 앱이 배치되는 공간

 

더 자세한 내용은 Tomcat 공식 문서를 참고해주세요!

https://tomcat.apache.org/tomcat-9.0-doc/architecture/overview.html

 

Apache Tomcat 9 Architecture (9.0.102) - Architecture Overview

This page provides an overview of the Tomcat server architecture. Tomcat is designed to be a fast and efficient implementation of the Servlet Specification. Tomcat came about as the reference implementation of this specification, and has remained rigorous

tomcat.apache.org


5. 동기/비동기? 블로킹/논블로킹?

이번 공부를 하며 가장 헷갈렸던 부분이 바로 이 개념들이다.  
어떤 블로그는 "비동기 처리", 또 다른 곳에서는 "논블로킹"이라고 표현한다.

하지만 이 두 개념은 서로 다른 관점에서 작동하는 개념이므로 정확히 구분해서 이해할 필요가 있다.

 

개념 정리

동기/비동기는 사용자 코드(비즈니스 로직)의 흐름에 대한 개념이다.

구분 의미 예시
동기 (Synchronous) 작업을 요청한 스레드가 결과를 기다림 식당에서 음식을 주문하고 그 자리에서 기다림
비동기 (Asynchronous) 작업을 요청한 후, 결과를 기다리지 않고 다른 작업 수행
-> 결과는 콜백 등으로 나중에 전달됨
음식 주문 후 진동벨 받고 밖에 나감

 

 

블로킹/논블로킹은 I/O 처리 방식 (네트워크, 디스크)에 대한 개념이다.

구분 의미 예시
블로킹 (Blocking) I/O 작업이 끝날 때까지 해당 스레드는 아무 일도 못 하고 기다림 Thread-1이 DB 응답 기다리는 동안
아무 일도 못 함
논블로킹 (Non-blocking) I/O 작업이 준비되지 않아도
스레드는 즉시 리턴하고 다른 작업 수행 가능
Thread-1이 요청 → 준비 안 됐음
→ 다른 요청 처리

 

Tomcat은 어디에 속할까?

Tomcat의 구조를 보면 크게 두 개의 레이어로 나뉜다:

레이어 설명
Coyote HTTP 요청을 수신하고 처리하는 입구 (Connector)
Catalina 실제로 서블릿을 실행하는 내부 Servlet Container

 

Coyote - 논블로킹 I/O 처리

  • Tomcat 8부터 Java NIO (Non-blocking I/O) 기반의 비동기 소켓 처리를 지원
  • 내부적으로 Selector 기반 구조로 동작함 ->I/O가 준비되지 않으면 해당 스레드는 즉시 반환하고 다음 요청을 탐색
  • 즉, "데이터 준비됬나요?" -> 아니면 다른 요청 먼저 처리
📦 Java NIO란?
- Java 1.4부터 도입된 비동기/논블로킹 I/O API
- 기존 BIO는 스레드가 I/O가 끝날 때까지 대기 → 비효율
- NIO는 준비되지 않은 요청은 건너뛰고, 나중에 Selector로 감지하여 처리 → 효율적

※ WebFlux도 Netty와 Java NIO 기반으로 동작한다. (다음 글에서 설명 예정)

Catalina: 동기 & 블로킹 처리

  • Catalina는 서블릿 스펙을 따름
  • 기본적으로 요청마다 하나의 스레드를 할당해 처리 -> 블로킹 기반
  • service(), doGet() 같은 메서드는 응답을 반환할 때까지 기다려야 함 -> 동기 방식

 

구성 요소 처리 방식 기술 스택 설명
Coyote (입구) 논블로킹 Java NIO 요청 수신 시, 준비된 요청만 처리. 스레드 낭비 없음
Catalina (처리) 블로킹 & 동기 Servlet API 요청당 스레드 1개 할당. doGet(), service() 처리 시 블로킹

 

Tomcat의 입구(Coyote)는 논블로킹으로,
내부 처리(Catalina)는 블로킹 & 동기 방식으로 작동하는 하이브리드 서버다.

6. 왜 우리는 Spring MVC를 쓰는가?

앞에서 우리는 자바 웹 개발의 핵심 기술인 Servlet과 이를 실행하는 Tomcat의 구조와 동작 원리를 배웠다.
그렇다면 Spring MVC는 왜 등장하게 되었을까?

핵심은 서블릿만으로는 웹 개발이 너무 불편하다는 점이다.

 

Servlet의 한계

1️⃣ 서블릿을 계속 생성해야 한다.

  • 클라이언트의 요청 경로(URI)가 달라질 때마다 새로운 서블릿 클래스를 만들어야 한다.
  • 예를 들어 /member, /user, /home 등 요청이 늘어날수록 서블릿 클래스도 계속 늘어나게 된다.
  • 라우팅과 요청 처리를 직접 관리해야 하므로 유지보수가 어렵고 생산성이 낮다.

2️⃣ 비즈니스 로직이 서블릿 내부에 혼재된다.

  • 서블릿 클래스 안에 요청 파싱, 로직 처리, 응답 생성 코드가 모두 뒤섞여 있다.
  • 예외 처리, 로깅, 인코딩 설정 등 공통 관심사도 각 서블릿마다 따로 구현해야 한다.
  • 결과적으로 중복 코드가 많아지고, 변경에 취약한 구조가 된다.

이러한 단점을 해결하기 위해 등장한 것이 바로 Spring MVC이며, 그 핵심은 프론트 컨트롤러 패턴을 적용한 DispatcherServlet이다.

 

프론트 컨트롤러 패턴

하나의 중앙 진입점이 모든 요청을 받아서 내부적으로 적절한 컨트롤러로 위임 처리하는 구조

  • 공통 로직(로깅, 예외처리, 인코딩 등)을 한 곳에서 일괄 처리할 수 있음
  • 요청 경로에 따라 동적으로 컨트롤러를 매핑하므로 유연하고 확장 가능함

Spring MVC에서는 이 구조를 DispatcherServlet이라는 핵심 컴포넌트로 구현하고 있다.

 

DispatcherServlet

Spring MVC에서는 이 프론트 컨트롤러 역할을 DispatcherServlet이 수행한다.

모든 HTTP 요청은 DispatcherServlet을 거쳐 흐름이 제어된다.

  1. 클라이언트가 HTTP 요청을 보낸다.
  2. 어떤 컨트롤러(Handler)가 이 요청을 처리할지 탐색한다.
  3. 해당 컨트롤러를 실행할 수 있는 어댑터를 결정한다.
  4. Controller로 비즈니스 로직 실행, 결과를 Model에 담고 view 이름을 반환한다.
  5. view 이름에 해당하는 실제 뷰(HTML, JSP)를 탐색한다.
  6. View 객체와 Model 데이터를 결합하여 View에게 전달한다.
  7. View가 렌더링된 결과를 클라이언트에게 전송한다.

 

Spring MVC는 DispatcherServlet을 중심으로 핸들러 탐색 → 비즈니스 로직 실행 → 뷰 렌더링까지의 전체 웹 요청 흐름을 유연하게 제어한다.

 이 글에서는 Servlet과 Tomcat의 구조 및 동작 원리를 중심으로 설명하였기 때문에, Spring MVC의 DispatcherServlet 구조는 흐름 위주로 간략히 정리했다.

DispatcherServlet 내부 구조나 동작 원리를 더 깊이 다루는 내용은 별도 포스팅에서 자세히 정리할 예정이다.

7. 결론

Servlet, Tomcat, Spring MVC까지 자바 웹 개발의 핵심 요소들을 모두 짚어보았다.

이제 우리는 HTTP 요청이 어떻게 처리되고, 그 흐름을 Spring이 어떻게 개선했는지를 명확히 이해했다.

 

다음 글에서는 Spring MVC와는 전혀 다른 구조인  

Spring WebFlux + Netty 기반의 논블로킹 비동기 처리 방식을 살펴보자.

'삽질로그' 카테고리의 다른 글

yml vs properties – 스프링 설정, 무엇이 더 나은 선택인가?  (0) 2025.04.15
Tomcat 해부학 - Spring Boot 안에 살아있다?  (0) 2025.04.09
Spring Boot 비동기 처리 = 스레드풀?  (0) 2025.03.16
여러 요청이 동시에 들어오면, Spring Boot는 어떻게 처리할까?  (2) 2025.03.09
RDS 보안 정책 때문에 접속 불가?  (0) 2025.03.04
'삽질로그' 카테고리의 다른 글
  • yml vs properties – 스프링 설정, 무엇이 더 나은 선택인가?
  • Tomcat 해부학 - Spring Boot 안에 살아있다?
  • Spring Boot 비동기 처리 = 스레드풀?
  • 여러 요청이 동시에 들어오면, Spring Boot는 어떻게 처리할까?
mingking2
mingking2
에러와 삽질 속에서 성장하는 응애 개발자의 성장 일지
  • mingking2
    Mingking의 삽질 기록
    mingking2
  • 전체
    오늘
    어제
    • 분류 전체보기 (19)
      • 삽질로그 (10)
      • 스타트업 응애기 (1)
      • 프로젝트 도전기 (2)
      • DB 모르는 백엔드 탈출기 (5)
      • 네트워크 (1)
  • 블로그 메뉴

    • 홈
    • 태그
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    server
    servlet
    spring
    플로우차트
    Sync
    RDB
    Async
    MVC
    연관관계
    n:m
    context
    CompletableFuture
    orm
    JPA
    Java
    Tomcat
    batch
    @JoinColumn
    WebSocket
    DB
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
mingking2
Tomcat은 그냥 서버가 아니다?
상단으로

티스토리툴바