NOTE이 글은 토비의 스프링, 스프링 공식 문서를 기반으로 작성되었음을 밝힙니다.
개요
프레임워크 기술은 두가지 방향으로 발전하고 있다. 하나는 유연성과 확장성에 중점을 두고 어느 종류의 시스템 개발, 환경, 요구조건에도 잘 들어맞을 수 있도록 재구성할 수 있는 범용적 프레임워크다. 유연한 아키텍처를 가지고 장기적으로 많은 인원이 큰 규모의 시스템을 개발할 때 적합한 프레임워크다.
반면에 다른 방향으로 발전하는 프레임워크도 있다. 루비 기반의 RoR을 필두로 하는 일체형 고속개발 프레임워크다. 이런 프레임워크는 기술에 대한 자기주장이 강하고 기술 선호도가 분명하다. 그래서 제한적인 기술만을 사용하도록 강제한다. 이런 프레임워크는 스타트업이나 MVP 개발에 적합하다.
스프링은 유연성과 확장성, 다양성에 무게를 두고 있는 프레임워크다. 스프링이 제공하는 주요 기능은 세부 전략을 변경해서 사용할 수 있도록 확장 포인트가 제공된다.
스프링을 잘 사용하는 비결은 이러한 스프링의 유연한 확장성을 최대한 활용해서 두 번째 스타일의 프레임워크를 지향하는 것이다. 무슨 뜻인가 하면, 스프링이 제공하는 유연하고 확장성이 뛰어난 구조를 이용해서 각 프로젝트에 맞는 최적화된 구조를 만들어내고, 관례를 따라 빠르게 개발 가능한 스프링 기반의 프레임워크를 만들어서 사용해야 한다는 뜻이다.
스프링의 창시자인 로드 존슨은 “항상 프레임워크 기반의 접근 방법을 사용하라”고 조언한다. 스프링이 좋은 프레임워크라니까 그냥 스프링이 제공하는 기능과 API만 그대로 가져다 쓰면 충분하다는 발상은 전혀 스프링답지 않다는 말이다.
토비의 스프링 vol2
스프링 MVC 아키텍처
스프링의 웹 기술은 MVC 아키텍처를 근간으로 하고 있다. MVC는 Model, View, Controller로 분리하고 이 세가지 요소가 서로 협력해서 하나의 웹 요청을 처리하고 응답을 만들어내는 구조다.
MVC 아키텍처는 보통 프론트 컨트롤러(front controller) 패턴과 함께 사용된다. 중앙집중형 컨트롤러를 프레젠테이션 계층의 제일 앞에 둬서 서버로 들어오는 모든 요청을 먼저 받아서 처리하게 만든다. 프론트 컨트롤러는 클라이언트가 보낸 요청을 받아서 공통적인 작업을 먼저 수행한 후에 적절한 세부 컨트롤러로 작업을 위임해주고, 클라이언트에게 보낼 뷰를 선택해서 최종 결과를 생성하는 등의 작업을 수행한다.
Spring MVC 동작 원리
스프링은 DispatcherServlet과 7가지 전략을 기반으로 한 스프링 MVC 프레임워크를 제공한다.
- 클라이언트의 요청을 DispatcherServlet이 받음
- DispatcherServlet은 요청된 URL을 HandlerMapping 객체에 넘기고, 호출해야 할 Controller 메소드(핸들러) 정보를 얻음.
- DispatcherServlet이 요청을 컨트롤러로 위임할 HandlerAdapter를 찾아서 전달함
- HandlerAdapter가 컨트롤러로 요청을 위임함
- 비지니스 로직을 처리함
- Controller 객체는 비즈니스 로직을 처리하고, 그 결과를 바탕으로 뷰(ex. JSP)에 전달할 객체를 Model 객체에 저장함.
- DispatcherServlet에게 view name을 리턴함.
- DispatcherServlet은 view name을 View Resolver에게 전달하여 View 객체를 얻음.
- View 객체는 해당하는 뷰(ex. JSP, Thymeleaf)를 호출하며, 뷰는 Model 객체에서 화면 표시에 필요한 객체를 가져와 화면 표시를 처리함.
getting deeper
- 보다 정확하게 표현한다면, HandlerMapping은 DispatcherServlet로부터 전달된 URL을 바탕으로 HandlerAdapter 객체를 포함하는 HandlerExecutionChain 객체를 생성하며, 이후 DispatcherServlet이 HandlerExecutionChain 객체로부터 HandlerAdapter 객체를 가져와서 해당 메소드를 실행하게 된다.
참고
최근 스프링은 대부분 뷰 없이, 서버로서만 기능하게 되어 아래와 같이 표현되기도 한다.
DispatcherServlet
스프링에서 프론트 컨트롤러의 역할을 하는 DispatcherServlet은 모든 클라이언트의 요청을 가장 먼저 받는다. 그리고 요청을 처리하기 위해 여러 전략 객체들과 협력한다.
DispatcherServlet의 DI 가능한 전략
스프링은 DispatcherServlet과 7가지 전략을 기반으로 한 스프링 MVC 프레임워크를 제공한다. DistpatcherServlet은 프론트 컨트롤러와 같이 서버로 들어오는 모든 요청을 먼저 받아서 처리한다. 이런 DispatcherServlet의 동작방식과 기능을 확장, 변경할 수 있도록 준비된 전략들이 존재한다.
- HandlerMapping
- HandlerAdapter
- ViewResolver
- HandlerExceptionResolver
- LocaleResolver
- ThemeResolver
- RequestToViewNameTranslator
Handler Mapping: 컨트롤러 선정
DispatcherServlet은 URL이나 파라미터 정보, HTTP 명령 등을 참고로 해서 어떤 컨트롤러에게 작업을 위임할 지 결정한다. 컨트롤러를 선정하는 것은 DispatcherServlet의 핸들러 매핑 전략을 이용한다. 스프링에서는 컨트롤러를 핸들러라고도 부른다. 웹의 요청을 다루는(handle) 오브젝트라는 의미다. 사용자 요청을 기준으로 어떤 핸들어에게 작업을 위임할지를 결정해주는 것을 핸들러 매핑 전략이라고 한다.
HandlerMapping은 HTTP 요청 정보를 이용해서 이를 처리할 핸들러 오브젝트, 즉 컨트롤러를 찾아주는 기능을 가진 DispatcherServlet의 전략이다. HandlerMapping은 컨트롤러의 타입과 상관없다. 하나의 HandlerMapping 전략이 여러 가지 타입의 컨트롤러를 선택할 수 있다는 뜻이다.
스프링은 기본적으로 다섯 가지 핸들러 매핑을 제공한다. 이 중에서 디폴트로 등록된 HandlerMapping은 BeanNameUrlHandlerMapping과 DefaultAnnotationHandlerMapping이다. 그 외의 HandlerMappnig을 사용하려면 HandlerMapping 클래스를 빈으로 등록해줘야 한다.
HandlerAdapter: 컨트롤러 호출
HandlerAdapter는 위 핸들러 매핑으로 선택한 컨트롤러/핸들러를 DispatcherServlet이 호출할 때 사용한다. 컨트롤러를 호출하려고 할 때, 컨트롤러의 타입은 제한이 없다. 호출 방법은 컨트롤러의 타입에 따라 달라지기 때문에 컨트롤러를 결정해도 DispatcherServlet이 호출방법을 알 수가 없다. 그래서 컨트롤러 타입을 지원하는 HandlerAdapter가 필요하다.
ViewResolver: 뷰 선택
ViewResolver는 컨트롤러가 리턴한 뷰 이름을 참고해서 적절한 뷰 오브젝트를 찾아주는 로직을 가진 전략 오브젝트이다. 디폴트로 등록된 InternalResourceViewResolver는 JSP나 서블릿 같이 RequestDispatcher에 의해 포워딩될 수 있는 리소스를 뷰로 사용하게 해준다.
HandlerExceptionResolver: 예외 처리
HandlerExceptionResolver 전략은 예외가 발생했을 때 이를 처리하는 로직을 갖고 있다. 예외가 발생했을 때 예외의 종류에 따라 에러 페이지를 표시한다거나, 관리자에게 통보해주는 등의 작업은 개발 컨트롤러가 아니라 프론트 컨트롤러인 DispatcherServlet을 통해 처리돼야 한다. DispatcherServlet은 등록된 HandlerExceptionResolver 중에서 발생한 예외에 적합한 것을 찾아서 예외처리를 위임한다.
디폴트 전략은 AnnotationMethodHandlerExceptionResolver, ResponseStatusExceptionResolver, DefaultHandlerExceptionResolver 세 가지가 등록되어 있다.
LocaleResolver: local 정보 설정
local 정보를 결정해주는 전략이다. 디폴트인 AcceptHeaderLocaleResolver는 HTTP 헤더의 정보를 보고 지역정보를 설정해준다. 이렇게 결정된 지역정보는 애플리케이션에서 활용될 수 있다. 이 전략을 바꾸면 지역정보를 HTTP 헤더 대신 세션이나, URL 파라미터, 쿠키 또는 XML 설정에 직접 지정한 값등 다양한 방식으로 결정할 수 있다.
ThemeResolver: 테마 선택
테마를 가지고 이를 변경해서 사이트를 구성할 경우 쓸 수 있는 테마 정보를 결정해 주는 전략이다. 자주 사용되지는 않지만, 테마를 적용하는 경우에 사용한다.
RequestToViewNameTranslator: 뷰 자동 생성
컨트롤러에서 뷰 이름이나 뷰 오브젝트를 제공해주지 않았을 경우 URL과 같은 요청 정보를 참고해서 자동으로 뷰 이름을 생성해주는 전략이다. 디폴트는 DefaultRequestToViewNameTranslator이다.
@MVC
스프링은 계속해서 최신 웹 기술과 새로운 자바 언어의 특징을 포용해서 다양한 전략이 추가되고 있다. 그 중 스프링이 2.5에서 처음 도입되어 3.0에서 강화된 어노테이션을 활용한 전략은 가장 혁신적인 발전이다.
어노테이션을 중심으로 한 새로운 MVC의 확장 기능은 @MVC라는 별칭으로도 불린다. 어노테이션 기반 MVC라는 의미다. @MVC는 스프링 3.0에서 기존에 가장 많이 사용되던 Controller 타입의 기반 클래스들을 대부분 대체하게 되었다. 물론 DispatcherServlet의 기본 전략 구조는 그대로 유지되고 있어 기존 전략을 활용하거나 커스텀 전략을 만들어서 사용할 수 있다. 이 부분은 다음 글에서 정리할 예정이다.
- 출처
토비의 스프링