[spring] 스프링 MVC 전체 구조

장선규·2022년 12월 27일
1

Spring

목록 보기
1/4
post-thumbnail

김영한님의 스프링 MVC 1편을 보면서 중요해보이는 부분을 메모하였다.

스프링의 MVC 구조를 파악하기 위해 직접 MVC 프레임워크를 간단하게 만드는 작업을 하였고, FrontControllerServlet을 앞 단에 두어 요청을 받는 식으로 프레임워크를 만들었다.
이때 점점 FrontControllerServlet을 개선하면서 실제 스프링 MVC 구조와 유사하게 바꿔갔다.

FrontControllerServletV5

// FrontControllerServletV5
@WebServlet(name = "frontControllerServletV5", urlPatterns = "/front-controller/v5/*")
public class FrontControllerServletV5 extends HttpServlet {
	private final Map<String, Object> handlerMappingMap = new HashMap<>(); // url:handler(controller) mapping
    private final List<MyHandlerAdapter> handlerAdapters = new ArrayList<>();  
...
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        // 1. 핸들러 가져오기 (조회)
        Object handler = getHandler(request);
        if (handler == null) {
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        // 2. 핸들러 어댑터 찾기
        MyHandlerAdapter adapter = getHandlerAdapter(handler);

        // 3. 핸들러 어댑터에서 모델뷰 추출 -> 4. 핸들러 어댑터를 통해 핸들러 실행 -> 5. 모델뷰 반환
        ModelView mv = adapter.handle(request, response, handler);

        String viewName = mv.getViewName(); // 논리 이름(new-form,...)

        // 6. 뷰 리졸버를 통해 뷰 찾기 -> 7. view 반환
        MyView view = viewResolver(viewName); // 논리 이름을 물리 이름으로 바꿔줌 (new-form -> /WEB-INF/views/new-form.jsp)

        // 8. 뷰 렌더링
        view.render(mv.getModel(),request,response);
    }
...

Spring MVC 전체 구조

동작 순서

  1. 핸들러 조회: 핸들러 매핑을 통해 요청 URL에 매핑된 핸들러(컨트롤러)를 조회한다.
// 1. 핸들러 가져오기 (조회)
        Object handler = getHandler(request);
        if (handler == null) {
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
    private Object getHandler(HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        return handlerMappingMap.get(requestURI); // URI에 맞는 핸들러 매핑
    }
  1. 핸들러 어댑터 조회: 핸들러를 실행할 수 있는 핸들러 어댑터를 조회한다.
// 2. 핸들러 어댑터 찾기
        MyHandlerAdapter adapter = getHandlerAdapter(handler);
   private MyHandlerAdapter getHandlerAdapter(Object handler) {
        for (MyHandlerAdapter adapter : handlerAdapters) {
            if (adapter.supports(handler)) {
                return adapter;
            }
        }
        throw new IllegalArgumentException("handler adapter not found. handler=" + handler);
    }
  1. 핸들러 어댑터 실행: 핸들러 어댑터를 실행한다.
	ModelView mv = adapter.handle(request, response, handler);
  1. 핸들러 실행: 핸들러 어댑터가 실제 핸들러를 실행한다.
  • 예를들어 ControllerV4HandlerAdapter 라는 핸들러 어댑터를 만든 경우
@Override
    public ModelView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException {
        ControllerV4 controller = (ControllerV4) handler;

        Map<String, String> paramMap = createParamMap(request);
        Map<String, Object> model = new HashMap<>();
        String viewName = controller.process(paramMap, model);

        ModelView mv = new ModelView(viewName);
        mv.setModel(model);

        return mv;
    }
이와 같은 코드가 실행될 것이다
  1. ModelAndView 반환: 핸들러 어댑터는 핸들러가 반환하는 정보를 ModelAndView로 변환해서 반환한다.

  2. viewResolver 호출: 뷰 리졸버를 찾고 실행한다.

  • JSP의 경우: InternalResourceViewResolver 가 자동 등록되고, 사용된다.
  1. View 반환: 뷰 리졸버는 뷰의 논리 이름을 물리 이름으로 바꾸고, 렌더링 역할을 담당하는 뷰 객체를 반환한다.
  • JSP의 경우 InternalResourceView(JstlView) 를 반환하는데, 내부에 forward() 로직이 있다.
 // 6. 뷰 리졸버를 통해 뷰 찾기 -> 7. view 반환
 	MyView view = viewResolver(viewName); // 논리 이름을 물리 이름으로 바꿔줌 (new-form -> /WEB-INF/views/new-form.jsp)
        
		...
        
private MyView viewResolver(String viewName) {
        return new MyView("/WEB-INF/views/" + viewName + ".jsp");
    }
  1. 뷰 렌더링: 뷰를 통해서 뷰를 렌더링 한다.
// 8. 뷰 렌더링
        view.render(mv.getModel(),request,response);

Reference
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1

profile
코딩연습

0개의 댓글