메뉴 바로가기 검색 및 카테고리 바로가기 본문 바로가기

한빛출판네트워크

IT/모바일

Spring으로 마이그레이션(Migration)(2)

한빛미디어

|

2007-05-16

|

by HANBIT

11,285

제공 : 한빛 네트워크
저자 : Ethan McCallum
역자 : 박찬욱
원문 : Migrating to Spring

[이전 기사 보기] Spring으로 마이그레이션(Migration)(1)

웹 티어 변경하기 : Spring MVC

Spring으로 된 정제된 구조와 데이터베이스 작업을 위한 코드를 갖게 되었고, 이제는 웹 티어를 추적할 시간입니다. 여기서 중심이 되는 클래스는 Spring MVC의 Controller 인터페이스입니다.
package org.springframework ...

interface Controller {

  public ModelAndView handleRequest(
    HttpServletRequest request ,
    HttpServletResponse response
  ) throws Exception ;
        
}
진입점인 handleRequest()는 스트럿츠의 Action 클래스나 내가 제작한 페이지 컨트롤러와 비슷한 선언부를 갖고 있습니다. 프레임워크에서는 서블릿 request와 response 객체를 제공하며, 비즈니스 로직의 처리 결과를 리턴하고 이 결과를 어떻게 화면에 보여줄 것인지에 대해 구현하고 있습니다. ModelAndView에서 Model은 비즈니스 객체 혹은 뷰 티어에서 사용될 데이터의 Map입니다. 샘플 코드에서 뷰는 JSP이지만, Spring MVC는 Velocity 템플릿과 XSLT를 지원하고 있습니다.

샘플 애플리케이션의 서블릿 페이지 컨트롤러는 매우 간단해서 Spring MVC의 힘이 확연하게 드러나지는 않습니다. 그러므로 수정된 페이지 컨트롤러는 가장 교과서적인 예제 수준에 그치고 있습니다.

이전 페이지 컨트롤러는 서블릿에서 JSP로 객체의 Map을 건네주는 전략을 비슷하게 사용하고 있습니다. 결과적으로 이 작업을 위해서 나는 JSP에 아무런 변화를 주지 않아도 되었으며, Spring에 특화된 태그 라이브러리를 사용하지도 않았습니다.

Spring 기반으로 새로 만든 페이지에서 이전 작업은 여전히 작동되지만, 아직 DAO를 받아오기 위해서 ObjectRegistry를 호출하고 있습니다. 순수 Spring의 세계에서 DAO는 여기서 보여주는 WEB-INF/SpringMVC-servlet.xml과 같은 웹에 특화된 XML 설정 파일에서 컨트롤러에게 할당된다.

충분히 해볼 수 있을 만큼 쉽게 들립니다, 그렇죠? 단지 객체 레지스트리에서 사용한 Spring 환경 설정 파일-spring-objectregistry.xml-을 web.xml에 다음과 같이 추가만 해주면 됩니다.

  
    contextConfigLocation
  
  
    classpath*:spring-objectregistry.xml
  

이제 spring-objectregistry.xml에 선언되어 있는 객체는 WEB-INF/SpringMVC-servlet.xml에서 인식할 수 있을 것입니다.

이 작업은 다른 문제를 만듭니다. MVC 레이어는 spring-objectregistry.xml과 SpringMVC-servlet.xml 파일을 하나의 ApplicationContext로 불러옵니다. 객체 레지스트리는 spring-objectregistry.xml을 다른 ApplicationContext에서 불러옵니다. 여기서 두 개의 ApplicationContext는 자신만의 영역을 갖고 존재하며, 기본적으로 다른 ApplicationContext에 되어 있는 빈의 정의는 서로 볼 수 없습니다.

이번에는 spring-objectregistry.xml에 정의되어 있는 객체가 두 번 호출되는 상황입니다. 일단 MVC 레이어에서 불려지고, 그 다음 객체 레지스트리에서 불려 집니다. 이제 spring-objectregistry.xml에 있는 저의 “싱글톤”은 실제로는 더 이상 싱글톤이 아닙니다. 예제 코드에서는 모두 무상태 겍체(stateless objects)이지만, 규모가 큰 애플리케이션에서는 몇 몇 싱글톤이 상태를 유지해야 하는 경우가 있습니다. 만약 이런 상태를 갖고 있는 객체를 한 번에 하나씩만 불러오지 않는 다면, 동기화 문제에 봉착하게 됩니다. 이런 객체가 특정 시점에 많은 리소스를 차지하는 오퍼레이션을 여러 번 수행된다면, 제 애플리케이션의 성능은 타격을 받게 될 지도 모릅니다.

제 첫 번째 대응은 ObjectRegistry가 필요하지 않도록 코드를 리팩토링 하는 것이었습니다. 이 리팩토링은 간단히 작업되었지만, 단지 예제를 통한 학습이었습니다. 더 큰 프로젝트--레지스트리를 삭제해야하는 한 작업이 단지 하나의 작업 업무에만 영향을 미치지 않는 것--에서 실험해보기 위해서 리팩토링을 끝까지 충실히 수행하기로 결정했고, 저는 어떻게 하면 이 두 세계(역 - 두 개의 ApplicationContext)에서 작업을 할 수 있는 알아냈습니다.

간단히 말하자면, 웹 티어(WEB-INF/SpringMVC-servlet.xml)에서 사용되는 ObjectRegistry의 객체(spring-objectregistry.xml)를 노출시키는 몇 가지 방법이 필요합니다. Spring의 해결책은 ApplicationContext들의 저장소인 BeanFactoryLocator입니다. 객체 레지스트리에 이 두 파일을 모두 전달하고, MVC 레이어에서는 BeanFactoryLocator에서 공용되는 객체를 불러옵니다.

일단, 명시적으로 spring-objectregistry.xml에서 명시적으로 불러오는 작업을 못 하도록 ObjectRegsitry를 변경합니다.
import org.springframework....BeanFactoryLocator ;
import org.springframework.
    ...ContextSingletonBeanFactoryLocator ;
import org.springframework.
    ...BeanFactoryReference ;

// 이것이 ApplicationContext 전에 위치합니다.
private final BeanFactoryReference _singletons ;

private ObjectRegistry(){

  // ContextSingletonBeanFactoryLocator는 beanRefContext.xml의 내용을 불러옵니다.
  BeanFactoryLocator bfl =
    ContextSingletonBeanFactoryLocator
      .getInstance() ;

  BeanFactoryReference bf =
    bfl.useBeanFactory( "OBJ_REGISTRY_DEFS" );
                         
  _singletons = bf ;

}

public Object get( final String key ){
  return( _singletons.getFactory().getBean( key ) ) ;
}
이 코드는 ApplicationContext를 BeanFactoryLocator에서 OBJ_REGISTRY_DEFS 이름으로 받아온 BeanFactoryReference로 교체합니다. 여기서 OBJ_REGISTRY_DEFS는 beanRefContext.xml로 호출되는 파일에 정의되어 있습니다.


  
    
      
        spring-objectregistry.xml
      
    
  

OBJ_REGISTRY_DEFS 빈은 원래 객체 레지스트리 설정 파일인 spring-objectregistry.xml을 뒤로 숨기고 있는 실제 ApplicationContext입니다. BeanFactoryReference에 있는 getBean()을 호출하는 것은 단지 그 안에 있는 ApplicationContext를 받아오는 작업입니다.

ObjectRegistry는 자체적으로 이 작업을 도와주고 있습니다. 웹 티어에서 OBJ_REGISTRY_DEFS를 사용하게 만들기 위해서는 web.xml에-웹 티어의 Spring 환경 파일인 SpringMVC-config.xml 중에서 객체를 인식할 수 있도록 정의하는-추가해야할 내용이 있습니다.

     
       parentContextKey
     
     
       OBJ_REGISTRY_DEFS
     
  

  

     
       locatorFactorySelector
     

     
       classpath*:beanRefContext.xml
     
  
첫 번째 추가한 내용은 웹 티어 Spring 환경 파일에게 현재 환경에서 찾을 수 없는 어떤 객체라도 OBJ_REGISTRY_DEFS 이름으로 BeanFactoryReference에서 호출할 수 있도록 해줍니다. 두 번째 내용은 클래스 패스에서 beanRefContext.xml란 이름의 어떤 파일이라도 프레임워크가 불러 올 수 있도록 해줍니다.

이제 spring-objectregistry.xml에 정의되어 있는 객체는 SpringMVC-config.xml에 있는 웹 티어 객체를 인식할 수 있게 되었습니다. 이것은 내가 한 단계에서 매우 중대한 영향을 미치는 작업을 시도하는 것 대신에, 느긋하게 ObjectRegistry에서 손을 땔 수 있다는 것을 의미합니다.

다루기 힘든가요? 예. 끈끈한 코드(glue code : 역-상호 연계성이 지나친 코드)인가요? 당신의 애플리케이션을 Spring으로 마이그레이션(migration)한다는 것의 의미는 이미 당신이 자신만의 싱글톤 레지스트리를 갖고 있다는 것인가요? 당연합니다. 이제 이 애플리케이션은 미래의 리팩토링에 대해서 안전히 보호되어 있습니다. ObjectRegistry의 삭제는 단지 ObjectRegistry의 클라이언트 코드에만 영향을 주게 될 것입니다.

그렇지만 주의할 점은 Spring 문서에서 BeanFactoryLocator는 매일 사용되는 것이 아니라고 언급하고 있다는 것입니다. 이 글에서처럼 마이그레이션 프로젝트에서만 사용될지도 모릅니다. 만약 당신이 새로운 애플리케이션에 Spring을 사용할 생각이라면, 애플리케이션 디자인은 시작할 때부터 적절한 IoC 주입(injection) 방법을 고려해 보는 것이 좋습니다.

실력 올리기 The Round-up

이전 애플리케이션과 비교해서 성공한 점 중 나는 첫 번째로 내 코드의 크기가 매우 줄어 든 것을 언급하고 싶습니다. 내 코드의 크기는 매우 줄어들었으며, 디버깅이 쉬워졌습니다. 더 나아가 Spring은 객체의 생성과 객체 룩업, 데이터베이스 커넥션과 같은 많은 부분의 핸들링을 가능하게 해주어서, 나는 시스템의 확장에 대한 걱정을 덜게 되었습니다. IoC를 통한 주입(Injection)은 테스트-특정 DAO 구현을 설정 파일을 통해서 다른 것으로 교체할 수가 있다- 또한 단순화시켜 줍니다.

더 높은 관점에서 보면, 나는 특정 Spring 컴포넌트에 대해서 신중히 생각할 수 있었습니다. 객체 룩업과 JDBC 템플릿은 비슷하게 보였고, 상당히 규모가 큰 프로젝트에서 객체 룩업과 데이버테이스 연결을 관리하기 위한 프레임워크 코드는 여러 공통점을 갖고 있습니다. Spring은 이 작업을 매우 유용하게-매우 자연스럽게- 만들어 줍니다. 우리가 이 글에서 봤던 것처럼, 우리는 이제 프로젝트에서 프로젝트로 코드를 복사함으로서 다시 작성해야 하는 작업이 필요 없어졌습니다. 여기에 추가된 이점으로, 우리의 친구 Spring은 생산성 강화에 촛점을 맞추고 우리 자신의 문제에 대해서만 걱정을 하게 도와주고 있습니다.(역-비즈니스 로직에 관련된 코드를 작성하는데 집중하게 해준다.)

Spring을 적용하면 얻게 되는 또 다른 장점은 모두 다 적용하거나 아예 하지 않거나 식의 노력을 하지 않아도 된다는 것입니다. Spring을 다른 티어에 영향을 주지 않으면서 각 애플리케이션 티어에 적용을 할 수 있고, 그렇기 때문에 나는 다른 작업을 하는 도중에도 어느 시점에서든지 특정 작업을 중지할 수 있었습니다. 예를 들어, Spring의 JDBC 템플릿을 도입하기를 원한다면, DAO만 교체하고 다른 코드는 전혀 수정할 필요가 없습니다.

나는 Spring 파티에 늦기는 했지만, 참석했다는 것만으로도 매우 기쁘게 생각하고 있습니다.

참조
저자 Ethan McCallum는 호기심 있는 어린이에서 호기심 있는 어른으로 성장했으며, 그의 열정은 기술에서 생애(인생의 발전)로 바뀌고 있다.
역자 박찬욱님은 현재 학생으로, 오픈 소스에 많은 관심을 가지고 있습니다. Agile Java Network에서 커뮤니티 활동을 열심히 하고 있고, 블로그(chanwook.tistory.com)를 재미있게 운영하고 있습니다.
TAG :
댓글 입력
자료실