본문으로 건너뛰기

· 약 6분

MVC 구현​

Reflection을 이용하여 Spring MVC와 유사한 기능을 구현하는 미션이었다.
미션의 목표는 다음과 같았다.

  • MVC 프레임워크를 구현하면서 내부 동작 원리를 학습한다.
  • 점진적인 리팩토링을 경험한다.

미션의 목표와 더불어 각 클래스들이 역할과 책임을 적절히 가지도록 하고, 패키지의 의존 방향을 고민하면서 미션을 진행하는 것에 중점을 두었다.

애너테이션 기반 프레임워크 만들기​

기존 코드에 ManualHandlerMapping이라는 서블릿을 직접 등록해서 사용하는 HandlerMapping 클래스가 있었고, 1단계에서는 애너테이션 기반의 AnnotationHandlerMapping을 구현해야 했기 때문에 @Controller, @RequestMapping을 Reflection을 이용하여 스캔하고, 핸들러 매핑을 등록하는 부분까지 진행해야 했다.
테오가 @GetMapping이나 @PostMapping 부분도 진행하면 재밌을 것 같다고 해서 같이 진행해 보았다.
추가로 미션 요구사항은 아니었지만 클래스 레벨에 적용된 @RequestMapping도 동작하도록 구현해보았다.

다음과 같은 Flow로 Handler(실제 요청을 처리하는 메서드) 등록을 진행한다.

  1. @Controller가 적용된 클래스의 정보를 스캔하여 반환한다.
  2. @Controller가 적용된 클래스의 @RequestMapping이 적용된 메서드들의 정보를 반환한다.
  3. 각 메서드들을 순회하며 HandlerKey(uri + httpMethod 정보)와 HandlerExecution(인스턴스 + 실행하려는 메서드)을 생성하여 Map<HandlerKey, HandlerExecution>에 추가한다.

AnnotationHandlerMapping의 initialize 메서드에서 Handler를 등록한다. 코드는 다음과 같다.

public void initialize() {
if (!initialized.compareAndSet(false, true)) {
return;
}

final Map<Class<?>, ControllerInstance> controllers = annotationScanner.scanControllers();
final Set<Method> methods = annotationScanner.scanHttpMappingMethods(controllers.keySet());
for (final Method method : methods) {
final ControllerInstance controller = controllers.get(method.getDeclaringClass());
final HandlerExecution handlerExecution = new HandlerExecution(controller.getInstance(), method);
final List<HandlerKey> handlerKeys = handlerKeyGenerator.generate(controller.getUriPrefix(), method);
handlerKeys.forEach(handlerKey -> handlerExecutions.put(handlerKey, handlerExecution));
}

log.info("Initialized AnnotationHandlerMapping!");
handlerExecutions.keySet().forEach(key -> log.info("key: {}, Handler: {}", key, handlerExecutions.get(key)));
}

Legacy MVC와 @MVC 통합​

2단계는 Legacy MVC와 AnnotationHandlerMapping을 통합하는 부분이었다.
기존의 MVC와 애너테이션이 적용된 MVC 두 개를 같이 사용할 수 있어야 헀다.
대략적인 흐름은 다음과 같다.

  1. DispatcherServlet.service(request, response) 호출
  2. HandlerMappings를 통해 입력받은 request에 해당하는 Handler 조회
  3. HandlerAdapters를 통해 Handler를 실행시킬 수 있는 HandlerAdapter 조회
  4. HandlerAdapter의.handle 메서드 실행
  5. View의 render 호출

웹 애플리케이션 발전 과정​

웹 애플리케이션의 발전 과정 대한 구구의 강의가 있었다.
간단하게 정리하자면 다음과 같은 흐름으로 웹 애플리케이션이 발전했다.

내용이 길어져서 다음 문서에 정리했다.

추상적인 개념 학습 방법​

직관적이지 않은 추상적인 개념을 학습할 때는 개념의 구현을 참고하면 학습에 도움이 된다고 한다.

개념구현
OOPJava
WASTomcat, Jetty
IoCSpring BeanFactory, Servlet Container, Framework
DISpring BeanFactory

정리​

지금까지 스프링의 DispatcherServlet의 동작을 이론적으로만 알고 있었는데, 실제로 구현해 보니 조금 더 이해가 잘 가는 것 같다.
이번 미션에서 나의 리뷰어는 루카, 리뷰이는 헤나였다.
매 단계마다 꼼꼼하게 리뷰해 준 루카에게 너무 감사하고, 헤나에게 이상한 리뷰를 많이 남긴 것 같은데 꼼꼼히 반영해줘서 감사하다.
오랫동안 기다려왔던 레벨 4 미션이 하나씩 마무리 될 때 마다 아쉬움이 남는다.