RicoCheesethe studio log · v2.0
Live · KRRead posts
목록으로
개발PUBLISHED · 2026년 7월 14일·10 MIN READ

[스프링 요청 파이프라인] 요청을 알맞은 곳으로 보내는 DispatcherServlet (3)

Spring MVC의 프론트 컨트롤러인 DispatcherServlet이 요청을 핸들러에 연결하고 응답 형식을 결정하는 과정을 정리한다.

#spring#java#backend#web#request-lifecycle
Sleek corporate building lobby with marble walls and glass windows

다시 로비 앞에서 #

2화에서는 손님이 정문 경비실(Filter)을 통과하는 이야기를 다뤘다. 경비실은 손님이 어디로 향하는지 관심 없이 들여보내도 되는 사람인지만 확인했다. 이제 손님은 건물 안으로 들어왔다. 그런데 이 건물에 몇 층 몇 부서가 있는지, 누구를 찾아가야 하는지 손님은 여전히 모른다.

그래서 로비에 안내데스크가 있다. 어느 부서를 찾는 손님이든, 일단 이 안내데스크 앞을 지나야 한다. 스프링에서 이 안내데스크에 해당하는 게 DispatcherServlet이다. 3화는 이 안내데스크가 정확히 무슨 일을 하는지 뜯어본다.

창구는 하나, 부서는 여럿이다 #

이 건물에는 부서가 여러 개 있다. 회원가입을 처리하는 부서, 게시글을 보여주는 부서와 결제를 담당하는 부서까지 제각각이다. 그런데 안내데스크는 부서마다 따로 있지 않다. 로비에 딱 하나, 모든 손님이 어느 부서를 찾든 일단 그 앞을 지나가야 하는 창구가 있을 뿐이다.

스프링도 똑같이 짜여 있다. 컨트롤러(담당 직원)는 회원가입 컨트롤러, 게시글 컨트롤러처럼 개수 제한 없이 늘어날 수 있지만, 그 앞단에서 요청을 받아 넘기는 창구는 DispatcherServlet 하나다. 입구를 하나로 몰아두면 좋은 점이 있다. 응답 형식을 어떻게 통일할지, 에러가 났을 때 어디로 보낼지 같은 공통 규칙을 그 한 곳에서만 정하면 된다는 것이다. 부서마다 담당 직원이 제각각 규칙을 정하게 두면, 나중에 회사 전체 규칙을 바꿀 때 부서를 일일이 찾아다녀야 한다. 개발자들은 이런 구조를 프론트 컨트롤러 패턴이라고 부른다.

방문 목적만 보고 담당자를 찾아낸다 #

안내데스크 직원은 손님이 어떤 사람인지, 무슨 일을 하다 왔는지는 관심 없다. 손님이 내민 방문 목적, 즉 "mypage 부서 방문"이라는 문장 하나만 본다. 그리고 손에 든 명부를 펼쳐서 "mypage는 3층 마이페이지팀 담당"이라고 찾아낸 뒤 "몇 층 몇 부서로 가시면 됩니다"라고 알려준다.

스프링에서 이 명부에 해당하는 게 HandlerMapping이다. 개발자가 컨트롤러 코드에 @GetMapping("/mypage")라고 적어두면 그 정보가 명부에 자동으로 올라간다. 손님이 /mypage를 들고 오면 DispatcherServlet은 이 명부를 뒤져서 담당자를 판단한다. 명부에 없는 주소로 손님이 오면 안내데스크는 "그런 부서는 없습니다"라고 돌려보낸다. 404 에러가 뜨는 순간이 바로 이 지점이다.

담당자를 부르고, 서류를 넘겨준다 #

담당자를 찾아내는 것과 그 담당자에게 실제로 일을 시작하게 만드는 것은 다른 일이다. 안내데스크는 명부에서 이름만 찾아주고 끝나지 않는다. 내선 전화를 걸어 "손님 한 분 올려보낼게요"라고 알리고, 손님이 들고 온 서류(요청 데이터)를 담당자가 알아볼 수 있는 형태로 정리해서 같이 넘긴다.

이 역할은 스프링에서 HandlerAdapter가 맡는다. 컨트롤러 메서드마다 파라미터를 받는 방식이 조금씩 다르다. 어떤 메서드는 URL의 일부를 받고, 어떤 메서드는 폼 데이터를 통째로 받는다. HandlerAdapter는 이 차이를 흡수해서 어떤 컨트롤러든 DispatcherServlet 입장에서는 그냥 실행 요청 하나 던지면 알아서 처리되는 것처럼 만들어준다.

받아갈 형태로 포장한다 #

담당자가 일을 끝냈다. 그런데 담당자 책상 위에 놓인 서류를 손님에게 그대로 던져줄 수는 없다. 손님이 웹브라우저로 접속했으면 화면에 그릴 HTML 페이지로 포장해야 하고, 앱이나 다른 서버가 보낸 요청이면 JSON 데이터로 포장해야 한다. 이 포장을 결정하고 실행하는 것도 안내데스크의 몫이다.

컨트롤러가 화면 이름만 반환하면 ViewResolver가 그 이름에 맞는 HTML 템플릿을 찾아 채우고, 컨트롤러가 데이터 객체를 그대로 반환하면 메시지 컨버터가 그걸 JSON으로 바꾼다. 담당자는 "이 서류 완성했습니다"라고만 넘기고, 손님이 받아갈 최종 형태로 바꾸는 판단은 전부 안내데스크가 한다.

접수창구에 미리 신호를 보낸다 #

로비를 지나 부서 앞에 서면 접수창구가 한 번 더 신분을 확인한다고 1화에서 예고했다. 그런데 그 접수창구가 언제 손님을 확인하고 언제 다시 배웅할지 정해서 알려주는 것도 사실 안내데스크다. 담당자에게 손님을 올려보내기 직전에 접수창구로 먼저 신호를 보내고, 담당자가 일을 끝내고 나면 다시 접수창구로 신호를 보낸다.

기술 용어로는 이렇다. DispatcherServlet은 컨트롤러(핸들러)를 실행하기 전과 후, 정해진 순서에 맞춰 Interceptor를 호출한다. Interceptor 스스로 언제 실행될지 판단하는 게 아니라, 안내데스크가 순서를 정해서 불러줄 때만 움직인다. 이 안내데스크는 사실 개발자가 직접 채용하는 자리도 아니다. 스프링 부트를 켜는 순간 이미 로비에 앉아 있는, 존재감 없는 중앙 교환원이다. 이 접수창구가 정확히 무슨 확인을 하는지는 4화에서 다룬다.

그래서 이게 왜 중요한데 #

실무에서 이 구조가 쓸모 있는 순간은 에러 화면을 마주쳤을 때다. 404가 뜨면 명부(HandlerMapping)에 그 주소가 없다는 뜻이고, 응답 형식이 이상하게 나온다면 ViewResolver나 메시지 컨버터 설정을 의심하면 된다. 컨트롤러 코드는 멀쩡한데 결과물이 이상하다면, 문제는 담당자가 아니라 안내데스크의 포장 단계에 있을 확률이 높다.

이 지도가 있으면 로그를 볼 때도 순서대로 짚어갈 수 있다. 정문은 통과했는지, 안내데스크에서 담당자를 제대로 찾았는지, 포장 단계에서 걸렸는지를 순서대로 확인하면 원인 후보가 절반 이상 줄어든다.

다음 화 예고 #

안내를 마친 안내데스크는 손님에게 몇 층 몇 부서로 가면 되는지 알려주고, 담당자에게 신호를 보내둔다. 4화에서는 손님이 그 부서 문 앞에서 마주치는 접수창구, Interceptor를 다룬다. 이 회사 직원인 접수창구가 경비실과 뭐가 다른지, 그리고 담당자를 만나기 직전 정확히 무엇을 확인하는지를 짚어본다.