본문 바로가기

CS/DesignPattern

(DesignPattern) FrontController - Version05 (with HandlerAdapter)

현재의 문제점 

Version03, Version04 모두 원래의 취지에 맞게 FrontController에서 각각의 역할에 맞는 컨트롤러에게 전달하고 해당 컨트롤러는 비즈니스로직만을 처리할 수 있도록 설계가 되었다.

하지만 아직 문제가 남아있다!

Version03, Version04 각각을 사용하고 싶을땐 아래의 사진과 같이 사용자가 직접 명시적으로 코드를 수정해야한다는 단점이 있다. 




해결방안


이를 개선하기 위해서 우리는 어댑터 패턴을 사용할 것이다.
어댑터 패턴을 사용을 사용하면 위와 같이 명시적으로 선언하지 않고도 컨트롤러를 매핑시킬 수 있다.

 

어댑터 패턴이란?

어댑터 패턴은 ControllerVersion03과 ControllerVersion04 같이 호환이 불가능한 경우에 이를 호환 가능하게 할 수 있도록 도와주는 패턴이다.

(어댑터 패턴에 대한 포스팅이 아니기에 자세한 내용이 궁금하다면 이전에 포스팅하였던 링크를 참고하길 바랍니다.)

jwdeveloper.tistory.com/228

 

(DesignPattern) 어댑터 패턴

어댑터란? 사전적 의미) 기계 기구 등을 다목적으로 사용하기 위한 부가 기구 프로그래밍적 의미) 이미주 어진 알고리즘을 Adapter를 이용해 원하는 기능으로 변경 알고리즘을 요구사항에 맞게 변

jwdeveloper.tistory.com


우리가 개선하고자 하는 바는 아래와 같다.
컨트롤러에 매핑할 핸들러 정보를 찾아서 어댑터를 통해서 컨트롤러(핸들러)에 접근한다.

  1. 클라이언트가 FrontController에 접근 
  2. 매핑할 핸들러 목록을 탐색
  3. 핸들러를 처리할 수 있는 어댑터를 탐색
  4. 컨트롤러 전송


구현 시작!

HandlerAdapter 생성

인터페이스

컨트롤러는 여러 개가 존재하기에 해당 컨트롤러에 맞는 각각의 어댑터가 존재한다.
이를 추상화한 MyHandlerAdapter 인터페이스를 생성한다.

  • 현재 어댑터가 요청한 핸들러를 처리할 수 있는지를 체크
  • 요청을 처리

 

구현 클래스

기존 Version03, Version04에서는 컨트롤러에 위임하는 처리를 FrontController에서 수행하였지만 이제 해당 과정을 Adapter에서 처리한다.

 

구현 어댑터

기존의 FrontController

기존의 FrontController Controller 위임 

FrontController 생성

  • 초기화
  • 매핑과 처리
  • 뷰 랜더링

FrontController는 위의 세 가지 과정으로 이루어진다.

 

초기화

아래와 같이 핸들러 매핑과 그것을 연결시켜줄 핸들러 어댑터를 초기화시킨다.

public FrontControllerVersion05() {
    initHandlerMappingMap();
    initHandlerAdapters();
}

핸들러 매핑, 핸들러 어댑터 초기화

매핑과 처리

빨간색은 요청에 맞는 핸들러를 찾는 과정이고

파란색은 찾은 핸들러의 어댑터를 찾는 과정이다.

마지막 녹색은 어댑터의 처리과정이다.

 

요청의 URI를 읽어서 요청에 맞는 Handler를 찾는 과정 

private Object getHandler(final HttpServletRequest request) {
    final String requestURI = request.getRequestURI();

    return handlerMappingMap.get(requestURI);
}

찾은 핸들러에 맞는 Adapter를 찾는 과정

private MyHandlerAdapter getHandlerAdapter(final Object handler) {
    final AtomicReference<MyHandlerAdapter> getHandler = new AtomicReference<>();
    handlerAdapters.iterator()
                   .forEachRemaining(myHandlerAdapter -> {
                       if (myHandlerAdapter.supports(handler)) {
                           getHandler.set(myHandlerAdapter);
                       }
                   });
    return getHandler.get();
}

 

이 결과 기존의 Version03, Version04에서 유연하지 못하였던 부분을 어댑터 패턴을 이용한 핸들러 매핑을 통해서 유연한 구조로 개선이 가능해졌다.

 

하기 링크는 이전에 Spring DispatcherServlet의 내부를 디버깅한 내용이다.
해당 내용을 보면 현재와 거의 유사한 구조로 스프링의 DispatcherServlet도 구성되어있다는 점을 알 수 있다.

 

jwdeveloper.tistory.com/117?category=835408

 

(SERVLET) DispatcherServlet의 내부 살펴보기

DispatcheServlet의 doService부터 시작 핸들러 찾기 요청을 찾아올 수 있는 핸들러를 찾아오는 부분 핸들러 매핑 찾기 - 기본으로 두 개의 핸들러 매핑이 제공된다. 두 가지 핸들러 중 찾은 핸들러는 Req

jwdeveloper.tistory.com

 


번외) Version03은 ModelView를 리턴하고 Version04는 뷰 네임을 반환하지 않았었나...?

맞다.

어댑터 패턴을 이용하면 이러한 부분을 유연하게 설계할 수 있다.

 

아래와 같이 뷰 네임을 감싸서 리턴하면 그만이다!


Code Link

github.com/mike6321/SpringMVC/commit/f3096cf0498295f644ce4a6eb4eaec6b62929958#diff-9b2e6637f4e656d5a2ddc5c37f24c54a159b2da4bc1c01d9460680bda3 4 b36 b7

 

(servlet) 유연한컨트롤러1 - version05 · mike6321/SpringMVC@f3096cf

Permalink This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository. Browse files (servlet) 유연한컨트롤러1 - version05 Loading branch information Showing 3 changed files with 159 additions and

github.com

github.com/mike6321/SpringMVC/commit/dcc2de28ded154e8d53d7dc58604e7d232bd84af#diff-9b2e6637f4e656d5a2ddc5c37f24c54a159b2da4bc1c01d9460680bda3 4 b36 b7

 

(servlet) 유연한컨트롤러2 - version05 · mike6321/SpringMVC@dcc2de2

Permalink This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository. Browse files (servlet) 유연한컨트롤러2 - version05 Loading branch information Showing 4 changed files with 79 additions and 1

github.com