Hello, Freakin world!

dispatch 기능 구현하기 본문

Toy Project/URL Mapping 프레임워크 구현하기

dispatch 기능 구현하기

johnna_endure 2020. 4. 1. 16:46
 public Response dispatch(Request request) {
        Method[] methods = RequestHandler.class.getMethods();
        Optional<Method> handlerOpt = findHandler(methods, request.getUrl(), request.getMethod());

        try {
            Method handler = handlerOpt.orElseThrow(() ->
                    new NotFoundException("url 에 해당하는 핸들러를 찾지 못했습니다."));
            return invoke(requestHandler ,handler, request);;
        } catch (NotFoundException e) {
            e.printStackTrace();
            return new Response(404, "not found handler");
        }
    }

코드의 뼈대는 다음과 같다. 

 

dispatch의 인수로 지정된 Request를 이용해 클라이언트의 요청 정보를 받고, 

요청 정보를 이용해 RequestHandler에 포함된 핸들러에 매핑한다. 

 

findHandler 메서드는 reflection과 Stream api을 이용해 RequestHandler에 등록된 메서드 중 

요청 정보를 만족하는 메서드가 있는지 탐색한다.

 

이는 Optional<Method>를 반환하고, 만족하는 메서드가 없는 경우 404 Not Found 예외를 던지도록 해주자.

아래는 findHandler 코드다.

private Optional<Method> findHandler(Method[] methods, String url, io.request.Method protocolMethod) {
        return Arrays.stream(methods)
                .filter(method -> method.isAnnotationPresent(RequestMapping.class))
                .filter(method -> method.getAnnotation(RequestMapping.class).method().equals(protocolMethod))
                .filter(method -> URLParser.validateUrl(method.getAnnotation(RequestMapping.class).url(), url))
                .findFirst();
    }

 

애너테이션을 이용한 프레임워크를 구성하는데 있어, findHandler 메서드는 핵심적인 역할을 한다.

 

살짝만 RequestHandler 클래스를 엿보고 오자.

public class RequestHandler {
 	...

    @RequestMapping(method = Method.GET, url = "/rooms")
    public Response getRooms(Request request) {
     	...
        return new Response(200, "success", responseBody);
    }

 	...
}

 

@RequestMapping 이라는 애너테이션의 속성에 식별 정보를 미리 지정하고 있다.

findHandler 메서드는 reflection api를 이용해 메서드에 마크된 애너테이션의 타입이 원하는 타입인지 확인하고,

Method(GET,POST 등의 값을 가지는 enum 클래스) 와 url 을 비교하고 있다.

 

이로서 다소 엉성하지만 그럴듯한 프레임워크가 완성됐다.

이렇게 dispatch 하는 기능이 없다면, 아마도 controller에서 if문을 이용해 핸들러를 분기하게 될 것이다.

이 방법은 갈수록 유지보수하기도 힘들고, 가독성도 떨어진다. 그리고 결국 클래스 간의 강결합을 유발하는 요인이 된다.

 

하지만 이 방식에서는 컨트롤러는 핸들러 정보에 대해서 전혀 몰라도 된다.

 

새로운 핸들러는 RequestHandler에만 추가하면 끝!

 

마지막으로 찾은 메서드를 invoke 하는 과정이 필요한데, 

이는 추가하려는 기능과 연관되는 부분이 있어 다시 살펴보도록 하자.

Comments