수업 복습

커맨드 객체 바인딩과 DI 흐름 정리

_김영인 2026. 1. 19. 15:24

 

 

이번 수업의 핵심은 “Spring MVC에서 요청이 들어오고 응답이 나가기까지 흐름이 어떻게 구성되는가”였다.

 

Servlet  / JSP 시절에는 FrontController와 Action을 직접 구현했지만 Spring MVC에서는 이 구조가 표준화된 흐름으로 정리되어 있다.


 

1. Spring MVC는 FrontController 패턴을 프레임워크가 제공한다

 

Spring MVC에서 DispatcherServlet은 FrontController 역할을 한다.

 

사용자의 요청이 컨트롤러로 바로 들어가는 게 아니라 DispatcherServlet이 먼저 요청을 받아서 처리 흐름을 통제한다.

 

정리하면 아래와 같다.

  • Servlet / JSP 시절: 개발자가 FrontController를 직접 구현
  • Spring MVC: DispatcherServlet이 FrontController 역할을 이미 수행

이 구조의 핵심은 요청 흐름의 “진입점”을 하나로 통일한다는 것이다.


 

2. 요청 처리 흐름을 3단계로 보면 이해가 쉽다

 

수업에서 정리한 흐름은 아래처럼 3단계로 볼 수 있다.

 

(1) [A] DispatcherServlet이 요청을 받는다

DispatcherServlet은 사용자의 모든 요청이 들어오는 첫 번째 관문이다.

그래서 수업에서 “유일한 서블릿”이라고 표현한 이유는 요청을 한 곳에서 통제하는 구조이기 때문이다.

 

 

(2) [B] HandlerMapping이 “누가 처리할지”를 찾아준다

DispatcherServlet은 요청을 받으면 바로 컨트롤러를 실행하는 게 아니라 먼저 HandlerMapping에게 물어본다.

  • “이 URL 요청을 처리할 컨트롤러가 누구야?”
  • “GET 요청인지 POST 요청인지도 확인해야 해”

HandlerMapping은 요청 URL과 HTTP Method를 보고 그 요청을 처리할 컨트롤러를 찾아서 연결해준다.

 

여기서 수업에서 말한 ActionFactory와 연결되는 포인트가 있다.

  • 예전 ActionFactory: 개발자가 if/switch로 직접 분기 (수동 라우팅)
  • Spring HandlerMapping: 매핑 정보 기반으로 자동 분기 (자동 라우팅)

ActionFactory 역할이 스프링에서는 HandlerMapping 구조로 정리된다고 이해하면 된다.

 

(3) [C] Controller가 요청을 처리하고, 어디로 갈지 결정한다

 

Controller는 예전 MVC 구조에서 Action 역할과 유사하다.

 

컨트롤러가 하는 일은 크게 두 가지다.

  • 요청 정보 (파라미터)를 추출해서 필요한 로직 수행
  • 처리 결과를 바탕으로 “어디로 갈지”를 결정해서 반환

Servlet / JSP 구조에서는 ActionForward 같은 객체로 이동 정보를 넘겼다면 Spring MVC에서는 컨트롤러가 뷰 이름 (String) 또는 ModelAndView를 반환하는 방식으로 흐름이 정리된다.


 

3. @RequestMapping → @GetMapping으로 바뀐 이유

 

수업에서 다룬 매핑 방식은 크게 두 가지였다.

기존 형태

 
@RequestMapping(value="/index.do", method=RequestMethod.GET)

 

축약 형태

@GetMapping("/index")
 

@GetMapping은 GET 요청 전용 매핑 방식이다.
기존의 RequestMapping을 더 짧고 명확하게 쓴 표현이다. 

이 흐름에서는 .do 패턴을 제거하면서 URL을 더 깔끔하게 가져가는 방향도 같이 연결됐다.


 

4. 요청 정보 추출이 “가벼워지는 이유” = 커맨드 객체 (VO / DTO)

 

Spring MVC에서는 요청 파라미터를 하나씩 꺼내는 방식이 아니라 DTO 형태로 한 번에 받을 수 있는 구조가 가능하다.

 

수업에서는 이를 다음처럼 정리했다.

  • VO (Value Object)
  • DTO (Data Transfer Object)
  • 커맨드 객체 (Command Object)

이 용어들은 수업 맥락에서 “요청 데이터를 담는 객체”라는 의미로 연결된다.

여기서 중요한 조건은 하나다.

 

DTO의 setter 이름과 요청 파라미터 이름이 맞아야 자동으로 바인딩된다.

 

예를 들어

  • name="mid" → setMid()
  • name="mpw" → setMpw()

이 구조 덕분에 컨트롤러는 request.getParameter()를 반복하지 않아도 입력을 받을 수 있고 전체 코드가 더 단순해진다.


 

5. 커맨드 객체에 DAO를 넣으면 안 되는 이유

 

수업에서 강조한 핵심은 “경량화”였다.

커맨드 객체는 원래 요청 데이터를 담는 역할이다.
그런데 커맨드 객체 안에 DAO 같은 의존 객체를 넣어버리면 문제가 생긴다.

 

대표적인 문제는 아래 두 가지다.

  • DAO가 여러 개 생성될 가능성이 커진다 (new가 늘어남)
  • AOP 같은 구조를 적용할 때 설계가 불편해진다

DTO는 DTO 역할만 하고 DAO / Service는 DI로 분리해서 관리하는 구조가 더 안전하다.


 

6. DI 관점에서 핵심: new를 없애고 “주입받는 구조”로 만든다

 

이번 수업에서 가장 중요한 메시지는 결국 이것이다.

 

new를 직접 쓰는 구조를 줄이고 DI로 객체를 주입받는 구조로 만든다.

 

이렇게 하면

  • 객체 생성 책임이 한 곳 (컨테이너)로 모이고
  • 중복 생성이 줄고
  • 구조 변경이 쉬워진다

특히 멤버 변수가 생겼다면

  • 생성자에서 초기화하거나
  • DI로 주입받는 구조로 만드는 것이 기본 원칙이다.

 

7. “어디로 갈지”만 결정하고 “어떻게 갈지”는 구조로 고정된다

 

Servlet / JSP에서 ActionForward로 “forward / redirect”까지 직접 다뤘다면 Spring MVC에서는 이동 방식이 더 단순하게 정리된다.

 

수업에서 말한 핵심은

  • 컨트롤러는 “어디로 갈지”를 중심으로 반환하고
  • 이동 방식은 일정한 규칙으로 처리된다

컨트롤러는 더 가벼워지고 전체 흐름은 프레임워크가 통제하는 구조가 된다.


 

8. 2-Layered 아키텍처 관점

 

수업에서 말한 Layer 구조는 다음처럼 정리된다.

  • Presentation Layer: Controller (요청 / 응답 담당)
  • Business Layer: Service (핵심 로직 담당)

그리고 보통 실제 구현에서는 DAO까지 포함되면서

  • Data Access Layer: DAO / Repository

형태로 확장된다.

이 구조를 가져가는 이유는 역할을 분리해서 유지보수성과 확장성을 확보하기 위함이다.


 

9. 루트 컨테이너 (Root Container)가 먼저 준비되는 이유

 

“루트 컨테이너”의 핵심은 이거였다.

서비스 / DAO처럼 DB 연결이 필요한 객체는 요청이 들어오기 전에 미리 준비돼야 한다.

 

그래서 스프링에서는

  • 비즈니스 레이어 (Service)
  • DB 접근 레이어 (DAO)

쪽이 루트 컨테이너에 잡히는 경우가 많다.


 

Spring MVC는 요청 흐름을 DispatcherServlet 중심으로 통제하고 Controller는 커맨드 객체로 가볍게 입력을 받고

Service / DAO는 DI로 주입받아 역할을 분리한다.