ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring 핵심 알기 - 3] HandlerAdapter란? HandlerAdapter분석(with. DispatherServlet)
    Spring/Spring Core 2024. 2. 23. 16:34
    728x90
    반응형

     

    시작에 앞서...

     

    왜 핸들러클래스 이름뒤에 adapter가 붙을까? 잘생각해보면 우리가 컨트롤러를 작성할때, 메소드이름 그위에 requestMapping등으로 url를 맵핑해준다.

     

    그렇다면 디스패처는 핸들러맵핑에 의해 찾은 컨트롤러의 메소드를 실행시켜야 하지않는가? 하지만 디스패치서블릿은 해당 컨트롤러에 메소드이름을 모른다.. 그래서 중간에 adapter를 이용해서 메소드를 실행시킨후 modelandview를 데이터를 돌려받는것이다. adapter패턴을 공부하면 이말이 무슨말인지 이해할것이다.

     

    DispatcherServlet에서 HandlerAdapter의 역할

    HandlerAdapter는 Spring MVC의 핵심 구성 요소 중 하나로, DispatcherServlet과 핸들러(컨트롤러) 사이의 어댑터 역할을 합니다. DispatcherServlet이 특정 요청에 대해 핸들러를 찾으면, HandlerAdapter는 해당 핸들러를 호출하고 그 결과를 처리할 수 있는 메커니즘을 제공합니다.

    주요 기능

    1. 핸들러 호출: DispatcherServlet이 매핑한 핸들러를 호출합니다.
    2. 호환성 제공: 다양한 유형의 핸들러(예: @Controller, HttpRequestHandler, SimpleController)와 호환되도록 합니다.
    3. 핸들러 메서드 실행: 적절한 핸들러 메서드를 실행하고 그 결과를 반환합니다.
    4. 모델과 뷰 처리: 핸들러의 실행 결과를 ModelAndView로 변환하여 뷰를 렌더링합니다.

    Spring MVC의 기본 HandlerAdapter 구현체

    1. RequestMappingHandlerAdapter: 주로 @RequestMapping이 적용된 메서드를 처리합니다.
    2. HttpRequestHandlerAdapter: HttpRequestHandler 인터페이스를 구현한 핸들러를 처리합니다.
    3. SimpleControllerHandlerAdapter: Controller 인터페이스를 구현한 핸들러를 처리합니다.

    HandlerAdapter의 내부 구조와 작동 원리

    RequestMappingHandlerAdapter를 예제로 사용하여 내부 동작을 설명하겠습니다.

    내부 동작 원리

    1. 매핑된 핸들러 메서드 호출: DispatcherServlet이 요청을 RequestMappingHandlerAdapter에 전달하면, RequestMappingHandlerAdapter는 해당 요청을 처리하는 적절한 핸들러 메서드를 찾고 실행합니다.
    2. 매개변수 바인딩: 요청의 매개변수를 핸들러 메서드의 인수에 바인딩합니다.
    3. 핸들러 메서드 실행: 바인딩된 매개변수를 사용하여 핸들러 메서드를 호출합니다.
    4. 결과 처리: 핸들러 메서드의 반환값을 ModelAndView 객체로 변환하고, 뷰를 렌더링할 준비를 합니다

     

     

     

    Spring MVC의 RequestMappingHandlerAdapter가 실제로 요청을 처리하는 과정

    과정 요약

    1. DispatcherServlet이 요청을 받음.
    2. HandlerMapping을 통해 적절한 핸들러를 찾음.
    3. HandlerAdapter를 사용해 핸들러를 실행함.
    4. RequestMappingHandlerAdapter가 핸들러 메서드를 호출하고 결과를 처리함.

    상세 처리 과정

    1. 요청 수신: 클라이언트가 서버로 HTTP 요청을 보냅니다.
    2. DispatcherServlet이 요청을 수신: DispatcherServlet은 프론트 컨트롤러로, 모든 요청을 받아 적절한 컨트롤러로 전달합니다.
    3. HandlerMapping을 통해 핸들러 찾기: DispatcherServlet은 요청 URL을 기반으로 핸들러를 찾습니다.
    4. HandlerAdapter를 통해 핸들러 호출: DispatcherServlet은 핸들러를 호출하기 위해 적절한 HandlerAdapter를 찾습니다. 여기서는 RequestMappingHandlerAdapter를 사용합니다.

    RequestMappingHandlerAdapter의 처리 과정

    handle 메서드 호출

    DispatcherServlet이 요청을 RequestMappingHandlerAdapter에 전달하여 처리합니다

    @Override
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return handleInternal(request, response, (HandlerMethod) handler);
    }

     

     

    handleInternal 메서드

    핸들러 메서드를 호출하기 위한 내부 처리를 합니다.

    protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
        // 초기화 작업
        ModelAndViewContainer mavContainer = new ModelAndViewContainer();
        WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
        ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
        
        // 핸들러 메서드를 감싸는 객체 생성
        ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
        invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        invocableMethod.setDataBinderFactory(binderFactory);
        invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
        
        // 모델 초기화
        modelFactory.initModel(webRequest, mavContainer, invocableMethod);
    
        // 핸들러 메서드 호출
        invocableMethod.invokeAndHandle(webRequest, mavContainer);
    
        // 결과 처리
        if (!mavContainer.isRequestHandled()) {
            ModelAndView mav = new ModelAndView(mavContainer.getViewName(), mavContainer.getModel());
            return mav;
        }
        return null;
    }

     

     

    핸들러 메서드 호출

    ServletInvocableHandlerMethod를 사용해 핸들러 메서드를 호출합니다.

     

    public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
        // 실제 핸들러 메서드 호출
        Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
        setResponseStatus(webRequest);
    
        // 반환값 처리
        if (returnValue != null) {
            mavContainer.setRequestHandled(false);
            this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
        } else {
            mavContainer.setRequestHandled(true);
        }
    }

     

    매개변수 바인딩 및 메서드 실행

    매개변수를 바인딩하고 핸들러 메서드를 실행합니다.

     

    protected Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
        // 매개변수 바인딩
        Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
    
        // 핸들러 메서드 실행
        return doInvoke(args);
    }
    
    private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
        // 매개변수 바인딩 로직
        // ...
        return new Object[]{/* 바인딩된 매개변수 */};
    }
    
    private Object doInvoke(Object... args) throws Exception {
        return this.method.invoke(this.bean, args);
    }

     

     


    HandlerAdapter
    는 Spring MVC의 핵심 구성 요소로, DispatcherServlet과 다양한 유형의 핸들러 사이의 어댑터 역할을 합니다. RequestMappingHandlerAdapter는 주로 @RequestMapping이 적용된 메서드를 처리하며, 매개변수 바인딩, 핸들러 메서드 호출, 결과 처리를 담당합니다. 이를 통해 Spring MVC는 유연하고 효율적인 요청 처리 메커니즘을 제공합니다.

    728x90
    반응형
Designed by Tistory.