1. 서론: 100개의 API, 100개의 if문?
지금까지 우리는 클라이언트의 요청(HTTP 메시지)을 읽고, 파싱하고, 리플렉션이라는 마법의 도구까지 손에 넣었습니다. 하지만 막상 파싱된 URI(예: /login, /join, /board)를 바탕으로 비즈니스 로직을 실행하려고 하니 막막해집니다.
만약 서버가 처리해야 할 API가 100개라면, RequestHandler 안에 if (uri.equals("/login")) { ... } else if (uri.equals("/join")) { ... } 처럼 100개의 분기문을 만들어야 할까요? 이는 유지보수 관점에서 끔찍한 일입니다. 이 문제를 과거의 선배 개발자들은 어떻게 해결했을까요?
2. 서블릿(Servlet)과 톰캣(Tomcat)의 진짜 정체
이 문제를 해결하기 위해 등장한 자바의 표준 규약이 바로 서블릿(Servlet)입니다. 서블릿은 '클라이언트의 요청을 처리하고 결과를 반환하는 자바 웹 프로그래밍 기술'입니다.
과거(CGI 시절)에는 요청이 올 때마다 무거운 '프로세스(Process)'를 통째로 복제해서 실행했기 때문에 사용자가 조금만 몰려도 서버가 뻗어버렸습니다. 이를 혁신하기 위해 톰캣(Tomcat, 서블릿 컨테이너)이 등장합니다.
우리가 작성한
WebApplicationServer가 소켓을 열어 연결을 받고, RequestHandler를 스레드(Thread)로 실행시키는 구조 기억하시나요? 이것이 바로 톰캣이 동작하는 핵심 원리입니다. 톰캣은 프로세스 대신 가벼운 스레드를 사용하여 서블릿 객체를 실행시킵니다.[면접 단골 질문] 톰캣은 스레드를 매번 새로 만들까요?
우리의 코드는 현재 new Thread().start()를 통해 매번 스레드를 생성합니다. 하지만 진짜 톰캣은 서버 메모리를 보호하기 위해 스레드 풀(Thread Pool)을 사용합니다. 미리 일정 개수(기본 200개)의 스레드를 만들어 두고, 요청이 오면 쉬고 있는 스레드를 할당해 준 뒤 작업이 끝나면 다시 반납받는 방식을 사용하여 성능을 극대화합니다.
3. 서블릿의 매핑 지옥과 한계
톰캣 덕분에 성능 문제는 해결되었지만, 초창기 서블릿에는 여전히 치명적인 단점이 있었습니다. 바로 1 URL = 1 서블릿 클래스라는 규칙 때문이었습니다.
/login을 처리하는 LoginServlet, /join을 처리하는 JoinServlet 등 URL이 늘어날 때마다 무수히 많은 클래스를 만들어야 했고, 이 연결 고리를 web.xml이라는 설정 파일에 일일이 다 적어주어야 했습니다. (이를 매핑 지옥이라고 부릅니다.)
4. 구원자, 프론트 컨트롤러(Front Controller) 패턴의 등장
매핑 지옥에 지친 개발자들은 아주 기발한 아키텍처 패턴을 고안해 냅니다. 바로 프론트 컨트롤러(Front Controller) 패턴입니다.
- 서버의 입구에 문지기 역할을 하는 단 하나의 대표 서블릿(DispatcherServlet)만 둡니다.
- 모든 요청은 일단 이 문지기가 다 받습니다.
- 문지기는 우리가 6편에서 배운 리플렉션(Reflection) 기술을 활용하여, 들어온 URI를 보고 알맞은 일반 자바 클래스(Controller)의 메서드를 쏙쏙 찾아내어 동적으로 실행(Invoke)해 줍니다.
이것이 바로 현재 전 세계에서 가장 많이 쓰이는 웹 프레임워크인 Spring MVC의 핵심 동작 원리입니다. 개발자는 더 이상 서블릿을 만들거나 web.xml을 건드릴 필요 없이, @GetMapping("/login") 같은 어노테이션 하나만 달아주면 스프링의 프론트 컨트롤러가 알아서 찾아가는 마법이 여기서 시작된 것입니다.
5. 다음 단계로
이제 목표가 아주 명확해졌습니다. 우리가 만들었던 RequestHandler의 역할을 더욱 고도화하여, 스프링의 심장인 DispatcherServlet(프론트 컨트롤러)을 직접 구현해 볼 차례입니다.
이전 편에서 파싱해 둔 HttpRequest 객체의 URI 정보를 꺼내고, 리플렉션을 이용해 알맞은 컨트롤러 메서드를 찾아 실행하는 동적 라우팅 시스템을 다음 포스팅에서 본격적으로 코딩해 보겠습니다!
'정리 > WAS' 카테고리의 다른 글
| 순수 Java로 WAS 구현 (9) - 프론트 컨트롤러에 Jackson 도입하기: 역직렬화와 리플렉션의 비밀 (0) | 2026.05.16 |
|---|---|
| 순수 Java로 WAS 구현 (8) - 프론트 컨트롤러(DispatcherServlet) 직접 구현과 HTTP 응답 조립 (0) | 2026.05.16 |
| 순수 Java로 WAS 구현 (6) - 프레임워크의 마법, 리플렉션(Reflection) 완벽 이해 (0) | 2026.05.15 |
| 순수 Java로 WAS 구현 (5) - HTTP 요청 파서(Parser) 구현과 3가지 트러블슈팅 (0) | 2026.05.15 |
| 순수 Java로 WAS 구현 (4) - 파싱(Parsing)을 위한 HTTP 메시지 구조 완벽 분석 (1) | 2026.05.14 |