Spring MVC에서 사용하는 ApplicationContext와 WebApplicationContext

보통 스프링 설정 파일이 최소한 두 개이상 있을 겁니다. xxx-servlet.xml 과 나머지로 나눌 수 있습니다. 그중에서 xxx-servlet.xml은 DispatcherServlet이 WebApplicationContext를 만들 때 사용하고, 나머지는  ContextLoaderListener 또는 ContextLoaderServlet이 일반적인 ApplicationContext를 만들 때 사용합니다.

이게 끝이 아닙니다. WebApplicationContext는 바로 이 ApplicationContext를 상속받아서 여러 서블릿들이 공통으로 사용하는 빈들을 사용할 수 있게 되는 겁니다. 따라서 만들어지는 순서도 중요한데, Listener가 아니라 ContextLoaderServlet을 사용했을 때는 load 머시기 설정 값에 1을 줘서 DispatcherServlet보다 먼저 만들게 해야 합니다. 그래서 WebApplicationContext를 만들 때 해당 ApplicationContext를 상속받아서 그 안에 있는 빈들을 사용할 수 있게 되겠죠.

이런 구조로 설계한 건, DispatcherServlet이 하나의 웹 애플리케이션에서 여러 개일 수 있기 때문입니다. 여러 개의 DispatcherServlet에서 공통으로 사용할 빈들을 상위에 있는 ApplicationContext에 선언해두고 공유할 수 있게 하는 거죠.

사용자 삽입 이미지
자. 그럼 여기서 문제

만약에 스프링 2.5 컨트롤러를 사용하고 있고 이 컨트롤러에 특정 @Aspect를 적용하고 싶을 때 해당 AOP 관련 설정(aop:autoproxy 머시기 엘리먼트 + @Aspect 빈 등록)은 xxx-servlet.xml과 applicationContext.xml 둘 중 어디에 둬야 할까요?

xxx-servlet.xml에는 컨트롤러 설정, 뷰 리졸버, 핸들러 맵퍼 등의 설정이 되어 있고, applicationContext.xml에는 서비스, DAO 등의 설정이 들어있습니다.
 
ㄱ. xxx-servlet.xml
ㄴ. applicationContext.xml
ㄷ. 어디에 두든지 상관없다.
ㄹ. 스프링 2.5 컨트롤러에는 Spring AOP를 사용할 수 없다.

정답은?? ㄱ 입니다. 왜냐면, applicationContext.xml을 사용해서 ApplicationContext를 만드는 순간에는 컨트롤러들이 미쳐 빈으로 등록되어 있지도 않기 때문에, 프록시를 만들 대상이 없습니다. 다시 말해, AOP 빈은 있지만, 이 AOP를 적용할 대상이 되는 빈이 없는겁니다. 따라서 컨트롤러들과 관련된 설정이 있는 xxx-servlet.xml에 해당 설정을 위치해야 합니다.

Service Layer

특징
– clinet에게 : clinet가 사용하기 쉽도록 시스템의 기능을 까칠하게(coarse grained interace) 표현해준다.
– system에게 : Service Layer의 메소드는 작업의 처리 가능한 단위(Transactional Unit)를 표현한다.
– Stateless : 실행시에 이 계층의 객체들이 여러 쓰레드를 다룰수 있다. 이때 Stateless 해야 어떤 쓰레드가 다른 쓰레드를 폐끼치는 것을 피할 수 있다.
– 하나의 Use Case를 Transactional Unit of work
– 이 계층을 사용함으로써 system과 client 간의 결합도를 줄인다.

종속성
– Domain Model, Persistence Layer
– View나 Web Layer에 종속성을 가지면 안된다.
– 프레임웍에 종속적인 코드가 필요없다.
사용자 삽입 이미지
Spring’s Support
– 거의없다.
– ApplicationContext는 Web Layer에 객체를 주입(Injection)한다.
– Transactional management, Performance monitoring, pooling을 원한다면 지원해 줄 수 있다.

Web Layer

Web Layer

이 계층에서 다루는 주요 기능 두가지
– Navigation Logic 담당
– Domain model 과 Service Layer의 중계자 역할

특징
– servlet 으로 간단하게 구현될 수 있다. 이런 servlet은 request 파라미터를 객체로 바꾸고 service 인터페이스의 메소드를 호출한다.
– 유저들을 위해서 비즈니스 exception들을 적당한 에러 메시지로 바꿔야 하는 책임도 있다.

Spring MVC가 하는 일
– Spring MVC는 request 파라미터를 비즈니스 로직이 직접 작동할 수 있는 POJO로 맵핑하는 등의 request 파라미터와 비즈니스 로직 계층간의 복잡한 메카니즘을 제공한다.
– Spring은 request들을 처리하고 확장이 편하도록 복잡한 업무 흐름을 구현하고 있다.

종속성
-Service Layer(web에서 받은 정보를 service layer에 전해 줄 domain 객체로 전환)
-Domain Layer
사용자 삽입 이미지Spring MVC Web Layer API
org.springframework.web.servlet.mvc.Controller 인터페이스
– HttpServletRequest와 HttpServletResponse를 받을 때 필요하다.
– client에게 정보를 돌려줄 때 ModelAndView 객체를 만든다.

User Interface Layer

Layers in a Spring MVC Application

User Interface Layer

The user interface layer is responsible for presenting the application to the end user. 이 계층은 web layer에서 생성된 응답을 유저가 요청한 양식으로 변환합니다. 예를 들어 휴대폰 사용자들을 위해서는 WML 또는 최소한 특화된 XHTML을 필요로 할 것입니다.

웹 개발자들에게 user interface layer 추상단계는 매우 중요합니다. user interface layer를 weblayer 의 sublayer로 생각하면 쉬울 것입니다. 이 책은 웹 에플리케이션에 초점을 맞췄기 때문에 이 계층을 따로 분리를 했으며 이 계층 만의 관심사와 특징들이 존재한다.

User Interface Layer는 최상위 계층입니다. 개념적으로 이 말은 유저(Client)에게 데이터를 보내기 전 마지막 계층 이라는 것입니다. 이 계층에 다다르기 전에 이미 비즈니스 로직과 트랜잭션이 처리가 되고 모든 자원들이 반환되었었을 것입니다.

이 계층이 마지막에 있는 것은 좋은 것입니다. 이 계층은 유저들에게 보내질 데이터를 원하는 양식으로 바꿔(rendering)줍니다. UI 계층은 다른 계층들과 분리 되어 있기 때문에 시스템은 계속해서 다른 요청들을 처리할 수 있습니다. 유저에게 보낼 응답을 랜더링 하는 것은 응답을 모아오는 행위(DB 커넥션 유지, 비즈니스 로직 처리 등등을 마말하는 거겠죠?? 긴가 민가 하네요. 응답을 처리하는 행위가 더 나르려나..)와 분리 되어 있다는 것입니다.

UI 계층을 분리 시키는 것은 현실적입니다. 여러가지 UI 랜더링을 위한 툴들이 존재하기 때문입니다. JSP, Velocity, Freemarker등에 종속되지 않고 UI 인터페이스를 사용하여 특정 랜더링 기술을 사용하여 UI를 변경하더라도 다른 계층들에 영향을 주지 않을 수 있습니다.

Spring MVC’s User Interface Layer

Spring MVC UI 관심사를 몇몇 주요 인터페이스들로 분리시킵니다. org.springframework.web.servlet.View 인터페이스는 에플리케이션의 view 또는 page 를 나타냅니다. 유저가 요청한 작업의 결과를 고객이 볼 수 있는 폼으로 전환하는 역할을 합니다.

[#M_View 인터페이스를 구현한 class들 펼쳐보기|닫기|

org.springframework.web.servlet
Interface View

All Known Implementing Classes:
AbstractExcelView, AbstractJasperReportsSingleFormatView, AbstractJasperReportsView, AbstractJExcelView, AbstractPdfView, AbstractTemplateView, AbstractUrlBasedView, AbstractView, AbstractXsltView, ConfigurableJasperReportsView, FreeMarkerView, InternalResourceView, JasperReportsCsvView, JasperReportsHtmlView, JasperReportsMultiFormatView, JasperReportsPdfView, JasperReportsXlsView, JstlView, RedirectView, TilesJstlView, TilesView, VelocityLayoutView, VelocityToolboxView, VelocityView, XsltView

_M#]

Model은 객체들의 이름의 집합입니다. 어떤 객체든지 Model 안에 있는 View로 랜더링 될 수 있습니다. Model은 일반적인 목적으로 설계되었기 때문에 어떠한 랜더링 기술과도 작업이 가능합니다. View 랜더링 툴킷은 Model안에 있는 각각의 객체들을 랜더링 합니다.

View 인터페이스는 완전히 일반적이고 특정한 뷰 랜더링에 종속되어 있지 않습니다. 각각의 뷰 기술들은 이 인터페이스를 구현한 클래스로 제공됩니다.  Spring MVC는 기본적으로 JSP, FreeMarker, Velocity, JasperReports, Excel, PDF를 지원합니다.

org.springframework.web.servlet.ViewResolver는 인디렉션을 하는 유용한 인터페이스를 제공합니다. ViewResolever는 뷰 개체들과 그들의 논리적인 이름간의 맵핑하는 기능을 제공합니다. 예를 들어 /WEB-INF/jsp/onSuccess.jsp 파일을 success라는 이름으로 참조 할 수 있도록 합니다. 이것은 실제 View 객체와 코드 내에서 그것을 참조하는 것을 decoupling 시킵니다. ViewResolver를 사용하여 보다 유연한 설정을 할 수 있습니다.

[#M_ViewResolver 인터페이스를 구현한 class들 펼쳐보기|닫기|

org.springframework.web.servlet
Interface ViewResolver

All Known Implementing Classes:
AbstractCachingViewResolver, AbstractTemplateViewResolver, BeanNameViewResolver, FreeMarkerViewResolver, InternalResourceViewResolver, JasperReportsViewResolver, ResourceBundleViewResolver, UrlBasedViewResolver, VelocityLayoutViewResolver, VelocityViewResolver, XmlViewResolver, XsltViewResolver

_M#]

Dependencies

View 계층은 일반적으로 domain 계층에 종속됩니다. 항상 그런 것은 아니지만, 보통 도메인 모델에 직접 접근하여 랜더링 하는 것이 편리합니다. Spring MVC를 사용하는 대부분의 편리함은 view가 도메인 객체에 직접 작업을 한다는 것으로부터 생깁니다.

1270538112.bmp

Summary

User interface 계층(View 계층이라고도 합니다.)은 유저를 위한 결과물의 랜더링을 책입집니다. Spring MVC는 다양한 view 랜더링 기술을 지원합니다. 중요한 인터페이스로는 org.springframework.web.servlet.View와 org.springframework.web.servlet.ViewResolver입니다. view기술들에 대해서는 7장과 8장에서 자세히 다룰것입니다.

Layers of Abstractions

Layers of Abstractions

Spring MVC 에플리케이션들은 여러 계층으로 나누어져있다. layer is a discrete, othogonal area of concern within an application. 여러 계층들은 에플리케이션의 추상화에 해당하며 인터페이스는 계층들간 상호작용의 규약을 제공한다. 어떤 계층들은 몇몇 다른 Layer들과 상호작용을 하지만 매우 중요한 계층은 모든 계층과 상호작용을 한다.
계층은 개념적인 경계선이고 물리적으로 떨어져 있을 필요는 없다.

A Layer is a logical abstraction within an application. A tier is best thought of as a physical deployment of the layers.

계층 구조로 생각하는 것이 에플리케이션의 전체 흐름을 개념화하는데 도움이 된다. 에플리케이션 계층들을 케잌처럼 쌓아 놓은 모습으로 보는 것이 가장 흔하고 편리한 방법이다.
Spring MVC 에플리케이션은 최소 다섯 개의 추상화된 계층을 가지고 있으며 각각은 다음과 같다.

  • user interface
  • web
  • service
  • domain object model
  • persistence


위 그림을 보면 Domain Model이 왼쪽에 세로로 서있는 것을 볼 수 있습니다. 이것은 다른 모든 계층들이 Domain Model 계층에 종속하기 때문입니다.
매우 중요한 계층인듯 합니다. 저런 경우에 AOP를 사용한다고 본 것 같은데 지금 저 계층들에 없는 tracjaction management, security같은 것은 AOP를 사용하여 뺏다고 하는데 Domain Model은 그럴만한 성격이 아닌가 보네요.

Layer Isolation

계층을 분리시키는 것은 에플리케이션을 보다 유연하고 테스트가 용이하도록 만듭니다. 이러한 분리는 계층 사이의 종속성을 최소화 함으로써 달성할 수 있습니다. 종속성 남발을 피할 수 있는 최소한 두가지 방법이 있습니다. 만약에 어떤 계층이 다른 여러 계층들에 종속하기 시작하면 다른 계층간의 상호작용을 추상화하는 새로운 계층을 만드는 것을 고려해 봅니다. 또 하나의 계층이 여러 계층들에서 사용된다면 Spring의 AOP를 사용하는 것을 어떨지 생각해 봅니다.
여기서 기억하야 할 것은 에플리케이션을 여러 계층으로 나누는 것은 decouple 된 설계를 만들어 낸다는 것입니다. 그렇게 함으로써 여러분의 에플리케이션이 보다 유연하고(확장이나 변동이 쉽고), 테스트가하기 편해집니다.

Java Interface As Layer Contract

에플리케이션의 계층을 나누는데 Java 인터페이스가 중요한 역할을 합니다. 인터페이스는 계층간의 규약이며 그들의 구현과 세부사항을 숨긴 채 계층 간의 작동이 유지될 수 있도록 합니다. 인터페이스에 의해 제공되는 low coupling의 이점에 대해서는 잘 알 고있을 것입니다. 그러나 여태까지 그러한 장점은 여태까지 인터페이스가 아닌 실제 구현된 클래스를 사용할 수 밖에 없는 상황이였기 때문에 잘 살리지 못했습니다. 하지만 Spring과 다른 DI 프레임웤을 사용한다면 가능합니다. Spring이 직접 에플리케이션의 코드 대신 객체의 생성에 대한 일을 해주기 때문입니다.
계층간의 규약을 인터페이스로 정의해두면 개발 시간을 단축시킵니다. 개발자들이 인터페이스에 맞춰 개발을 하기 때문에 그것을 구현한 코드가 작성되고 바뀌고 테스트되더라도 개발이 가능하기 떄문입니다.
계층간의 상호작용을 인터페이스로 정의해 두면 단위 테스트가 간편합니다. EasyMock과 같은 프레임웤을 사용하여 쉽게 인터페이스의 구현체를 만들어서 테스트할 수 있기 때문입니다.
인터페이스를 사용하여 계층에 접근하는 것은 컴파일 시간을 단축시키고 보다 모듈화된 개발을 가능케 합니다. Client code가 이미 사용하고 있는 것들을 재컴파일하지 않아도 새로운 클래스를 추가하거나 변경이 가능하기 때문입니다.
인터페이스를 사용하면 또한 시스템이 매우 유연해 집니다. 시스템이 시작할 때 또는 이미 실행 중일 때도 특정 구현체로 변동이 가능합니다. Client code가 인터페이스에 맞춰 컴파일 되었기 때문에 실행중에도 구현된 클래스를 바꿀수가 있습니다. 매우 동적인 시스템을 만들수가 있습니다.

여기까지 매우 간단하게 요약하자면 인터페이스를 사용하여 각 계층간의 규약을 정의한다. 인터페이스는 계층의 추상화를 제공하고 계층을 구현한 것이 다른 계층에 영향을 주지 않고 쉽게 변할 수 있도록 허용한다.