봄수의 연구실

DispatcherServlet은 어떻게 View와 Controller를 구별할까 본문

DEV/Java

DispatcherServlet은 어떻게 View와 Controller를 구별할까

berom 2023. 7. 5. 18:25
- <a href="https://berom.tistory.com/251">DispatcherServlet</a>은 class의 annotation 유무를 보고 구분을 한다

실제 코드는 Github 링크를 참고하면 된다!

아래는 예제 프로젝트의 파일들이다.
딱 보니, 여러 개의 controller와 Spring의 @RequestMapping이 보인다

프로세스

public static void main(String[] args) throws Exception {
        Scanner sc = new Scanner(System.in);
        String uri = sc.nextLine();

        Set<Class> classes = componentScan("ex03");
        findUri(classes, uri);

    }

처음 프로젝트를 실행시키면, URI 입력 받고, 입력 받은 데이터를 잘라서 findURI에 넣는다
또한, ex03 프로젝트를 scan해서 클래스들 또한 입력한다

이제 우리가 주목해야 할 것은 App.java의 finduri이다.

public static void findUri(Set<Class> classes, String uri) throws Exception {
        boolean isFind = false;
        for (Class cls : classes) {
            if (cls.isAnnotationPresent(Controller.class)) {
                Object instance = cls.newInstance();
                Method[] methods = cls.getDeclaredMethods();

                for (Method mt : methods) {
                    Annotation anno = mt.getDeclaredAnnotation(RequestMapping.class);
                    RequestMapping rm = (RequestMapping) anno;
                    if (rm.uri().equals(uri)) {
								if(mt.isAnnotationPresent(ResponseBody.class)){
	                        mt.invoke(instance);
	                        return MessageConverter.convert(result)
								}
	                     else{
		                    String fileName = (String) mt.invoke(instance);
		                    return ViewResolver.convert(fileName);
							  }
                    }
                }
            }
        }
        if(isFind == false){
            System.out.println("404 Not Found");
        }
    }

프로젝트 내부의 클래스를 순회하면서 일단 controller 어노테이션이 있는지 찾는다
Controller를 조회하는 것이다

만약 Controller가 있다면, 클래스의 인스턴스를 생성하고, 메소드를 배열에 저장한다

if (cls.isAnnotationPresent(Controller.class)) {
	 Object instance = cls.newInstance();
	 Method[] methods = cls.getDeclaredMethods();

다음은 역시 해당 메소드에 RequestMapping 어노테이션을 갖고 온다.
이제 매개변수로 전달 받은 URI와 RequestMapping의 URI가 동일한지 확인한다

for (Method mt : methods) {
  Annotation anno = mt.getDeclaredAnnotation(RequestMapping.class);
  RequestMapping rm = (RequestMapping) anno;
  if (rm.uri().equals(uri)) {
		// 아래 코드가 있습니다
  }
}

if (rm.uri().equals(uri)) 내에서는 Response Body 어노테이션이 붙어있으면 메시지 컨버터를 발동시킨다
그렇지 않다면 뷰 리졸버를 발동시킨다!

	if(mt.isAnnotationPresent(ResponseBody.class)){
	// 메시지 컨버터 발동
		mt.invoke(instance);
		return MessageConverter.convert(result)
	}
	else{
	// 뷰 리졸버 발동
	  String fileName = (String) mt.invoke(instance);
	  return ViewResolver.convert(fileName);
  }

Converter가 뭔데?

예시로 ViewResolver의 Converter를 보자

위의 코드를 보면, Object를 json으로 변경 시켜준다.
변경 된 데이터를 buffer에 담아서 html로 읽어 반환해버린다

결론

Spring에서 요청이 들어오면, 아래의 흐름으로 처리가 된다

  • 톰켓(sockt으로 구성,request 객체 생성 후 반환) -> 필터 -> DispatcherServlet - controller - service - repository

[[DispatcherServlet]]이 이렇게 중요하다…!
중간에서 적절하게 경로를 라우팅 해줌으로써 유지보수가 수월해지게 해준다

이래서, 사람들이 Spring을 사랑하나보다

부족한 점이나 잘못 된 점을 알려주시면 시정하겠습니다 :>

728x90

'DEV > Java' 카테고리의 다른 글

Meta 어노테이션  (0) 2023.07.07
IoC  (0) 2023.07.07
DispatcherServlet 왜 필요한가  (0) 2023.07.05
Spring의 @RequestMapping  (0) 2023.07.05
Spring Security  (0) 2023.07.04