본문 바로가기

Java/Spring

[Spring] 스프링 MVC의 기본 구조

- 스프링은 하나의 기능을 위해서만 만들어진 프레임워크가 아니라 '코어'라고 할 수 있는 프레임워크에 여러 서브 프로젝트를 결합해서 다양한 상황에 대처할 수 있도록 개발되었다.

- 서브 프로젝트라는 의미를 개발자의 입장에서 가장 쉽게 이해할 수 있는 방법은 '별도의 설정이 존재할 수 있다'라는 개념이다.

- Spring Legacy Project로 생성한 예제의 경우에도 servlet-context.xml과 root-context.xml로 설정 파일이 분리된 것을 볼 수 있다.

- 스프링 MVC가 서브 프로젝트 이므로 구성 방식이나 설정 역시 조금 다르다.

 


스프링 MVC 프로젝트의 내부 구조

- 스프링 MVC 프로젝트를 구성해서 사용한다는 의미는 내부적으로 root-context.xml로 사용하는 일반 Java 영역(흔히 POJO(Plain Old Java Object)과 servlet-context.xml로 설정하는 Web 관련 영역을 같이 연동해서 구동하게 된다.

- 바깥쪽에 있는 WebApplicationContext라는 존재는 기존의 구조에 MVC 설정을 포함하는 구조로 만들어진다.

- 스프링은 원래 목적 자체가 웹 애플리케이션을 목적으로 나온 프레임워크가 아니기 때문에 달라지는 영역에 대해서는 완전히 분리하고 연동하는 방식으로 구현되어있다.

 


프로젝트의 로딩 구조

 

- XML

 

- 프로젝트 구동 시 관여하는 XML은 web.xml, root-context.xml, servlet-context.xml 파일이다.

- 이 파일들 중 web.xmlTomcat 구동과 관련된 설정이고, 나머지 두 파일은 스프링과 관련된 설정이다.

 

 

web.xml

- 프로젝트의 구동은 web.xml에서 시작한다.

- web.xml의 상단에는 가장 먼저 구동되는 Context Listener가 등록되어 있다.

 

- <context-param>에는 root-context.xml의 경로가 설정되어 있고, <listener>에는 스프링 MVC의 ContextLoaderListener가 등록되어 있다.

- ContextLoaderListener는 해당 웹 애플리케이션 구동 시 같이 동작하므로 해당 프로젝트를 실행하면 가장 먼저 로그를 출력하면서 기록한다.

 

- root-context.xml이 처리되면 파일에 있는 Bean설정들이 동작하게 된다.

 

- root-context.xml에 정의된 객체(Bean)들은 스프링의 영역(context) 안에 생성되고, 객체들 간의 의존성이 처리된다.

- root-context.xml이 처리된 후에는 스프링 MVC에서 사용하는 DispatcherServlet 이라는 서블릿과 관련된 설정이 동작한다.

 

 

web.xml

- org.springframework.web.servlet.DispatcherServlet 클래스는 스프링 MVC의 구조에서 가장 핵심적인 역할을 하는 클래스이다.

- 내부적으로 웹 관련 처리의 준비 작업을 진행하는데 이때 사용하는 파일이 servlet-context.xml이다.

 

 

- DispatcherServlet에서 XmlWebApplicationContext를 이용해서 servlet-context.xml을 로딩하고 해석하기 시작한다.

- 이 과정에서 등록된 객체(Bean)들은 기존에 만들어진 객체(Bean)들과 같이 연동되게 된다.

 


스프링 MVC의 기본 사상

 

- Servlet/JSP에서는 HttpServletRequest / HttpServletResponse라는 타입의 객체를 이용해 브라우저에서 전송한 정보를 처리하는 방식을 사용한다. 스프링 MVC의 경우 이 위에 하나의 계층을 더한 형태가 된다.

 

- 스프링 MVC를 이용하게 되면 개발자들은 직접적으로 HttpServletRequest/HttpServletResponse 등과 같이 Servlet/JSP의 API를 사용할 필요성이 현저하게 줄어든다.

- 스프링은 중간에 연결 역할을 하기 때문에 이러한 코드를 작성하지 않고도 원하는 기능을 구현할 수 있게 해준다.

 

- 개발자의 코드는 스프링 MVC에서 동작하기 때문에 과거에는 스프링 MVC의 특정한 클래스를 상속하거나 인터페이스를 구현하는 형태로 개발할 수 있었지만, 스프링 2.5버젼부터 등장한 어노테이션 방식으로 인해 최근 개발에는 어노테이션이나 XML 등의 설정만으로 개발이 가능하게 되었다.

 


모델2와 스프링 MVC

- 스프링 MV는 내부적으로 Servlet API를 활용하는데, '모델2' 방식으로 처리된다.

- 모델2 방식은 '로직과 화면을 분리'하는 스타일의 개발 방식이다.

 

모델2의 기본 구조

- 모델2 방식에서 사용자의 Request는 특별한 상황이 아닌 이상 먼저 Controller를 호출하게 되는데, 이렇게 설계하는 가장 중요한 이유는 나중에 View를 교체하더라도 사용자가 호출하는 URL 자체에 변화가 없게 만들어주기 때문이다.

- 컨트롤러는 데이터를 처리하는 존재를 이용해서 데이터(Model)를 처리하고 Response 할 때 필요한 데이터(Model)를 View쪽으로 전달하게 된다.

- Servlet을 이용하는 경우 개발자들은 Servlet API의 RequestDispatcher 등을 이용해서 이를 직접 처리해 왔지만 스프링MVC는 내부에서 이러한 처리를 하고, 개발자들은 MVC의 API를 이용해서 코드를 작성하게 된다.

 

 

스프링 MVC의 기본구조

[1]

 - 사용자의 Request는 Front-Controller인 DispatcherServlet을 통해서 처리한다.

 - 생성된 프로젝트의 web.xml을 보면 Request를 DispatcherServlet이 받도록 처리하고 있다.

 

[2], [3]

 - HandlerMapping은 Request의 처리를 담당하는 컨트롤러를 찾기 위해서 존재한다.

 - HandlerMapping 인터페이스를 구현한 여러 객체들 중 RequestMappingHandlerMapping 같은 경우는 개발자가 @RequestMapping 어노테이션이 적용된 것을 기준으로 판단하게 된다.

 - 적절한 컨트롤러가 찾아졌다면 HandlerAdapter를 이용해서 해당 컨트롤러를 동작시킨다.

 

[4] 

 - Controller는 개발자가 작성하는 클래스로 실제 Request를 처리하는 로직을 작성하게 된다.

 - 이때 View에 전달해야 하는 데이터는 주로 Model이라는 객체에 담아서 전달한다.

 - Controller는 다양한 타입의 결과를 반환하는데 이에 대한 처리는 ViewResolver를 이용하게 된다.

 

[5] 

 - ViewResolver는 Controller가 반환한 결과를 어떤 View를 통해서 처리하는 것이 좋을지 해석하는 역할을 한다.

 - 가장 흔하게 사용하는 설정은 servlet-context.xml에 정의된 InternalResourceViewResolver이다.

servlet-context.xml

 

[6], [7]

 - View는 실제로 응답 보내야 하는 데이터를 jsp 등을 이용해서 생성하는 역할을 하게 된다.

 - 만들어진 응답은 DispatcherServlet을 통해서 전송하게 된다.

 

 

 

- 모든 Request는 DispatcherServlet을 통하도록 설계되는데, 이런 방식을 Front-Controller 패턴이라고 한다.

- Front-Controller 패턴을 이용하면 전체 흐름을 강제로 제한할 수 있다. 예를 들어 HttpServlet을 상속해서 만든 클래스를 이용하는 경우 특정 개발자는 이를 활용할 수 있지만 다른 개발자는 자신이 원래 하던 방식대로 HttpServlet을 그대로 상속해서 개발할 수도 있다.

 - Front-Controller 패턴을 이용하는 경우에는 모든 Request의 처리에 대한 분배가 정해진 방식대로만 동작하기 때문에 좀 더 엄격한 구조를 만들어 낼 수 있다.