본문 바로가기

IT 살이/04. 기술 - 프로그래밍

개발 프레임워크 만들기 대장정 18 - Unity 구조 정리

뭔가 아쉽다. 쉽게 쓰려고 했는데, 배가 산으로 가버린듯한 기분이다. 아직 Unity 컨테이너 구조가 어떻게 되었는지 머리에 들어오지 않는 사람이 있을 듯하다. 그래서 이번 포스트에서는 Unity 구조를 필자가 파악하고 있는 한도내에서 좀 간단히 정리하려고 한다.

Unity  컨테이너에서는 프로그램적으로 모든 필요한 환경 설정을 할 수 있는 방법을 지원하지만 주로 설정을 위해서는 cofiguration을 이용한다.  다음 그림은 Unity 구성을 간단하게 표현해보았다.

■Config 타입 등록

그림의 좌측에는 config 설정이 있다. 프로그램이 실행되기 시작하면 이곳에 설정된 정보는 컨테이너로 등록된다. 등록이 완료되고 나면 컨테이너에 익스텐션도 몇개 그림처럼 확장되어 있을 것이다. 그림에 configuration의 Configure() 메소드가 호출되고 있다는 것을 보여주고 있다. 이게 뭐냐면....

코드상에는 config의 각 요소에 해당하는 타입이 정의되어 있다.

UnityConfigurationSection

UnityContainerElement

UnityTypeElement

UnityContainerExtensionElement

UnityContainerExtensionConfigurationElement  등등

이 타입들은 인터페이스를 하나 구현하고 있는데, IContainerConfigurationCommand이다. 이 인터페이스 정의는 다음과 같다.

public interface IContainerConfigurationCommand

{

    void Configure(IUnityContainer container);

}

각 요소의 타입에서는 Configure() 메소드를 구현해야 한다. 이 메소드의 인자로는 요소가 등록되어야 하는 컨테이너 참조가 건네진다. 각 요소의 타입의 Configure()에서는 컨테이너에 자신을 등록하는 작업을 해야 한다. 또한 요소 자신이 포함하고 있는 자식 요소들이 있다면 모든 자식들의 Configure()를 호출해서 스스로 컨테이너에 등록하는 작업을 하도록 해줘야 한다. 그리고 그 자식은 또한 자신의 자식들의 Configure()를 호출해주는 작업을 해야 하고....도미노 게임같은 상황이 떠오르지 않나?

도미노 게임의 첫번째 요소는 <unity/>요소에 해당하는 타입 UnityConfigurationSection 부터이다. 이 객체의 Configure()를 호출하면 그 이하의 자식들은 알아서 컨테이너로 등록된다. Program.cs 파일등에는 다음과 같은 유사한 코드가 있는데 바로 도미노의 시작부분이다.

// config 정보 읽어들이기

UnityConfigurationSection section;

section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");


//Unity 컨테이너에 config 정보를 설정한다.

section.Containers.Default.Configure(stdContainer);

타입을 등록하면 기본적으로 인스턴스가 생성되지는 않는다. 단지 타입만 등록된다. 이것이 기본적으로 구현되어 있는 거동(behavior, 거동이란 번역이 어렵나?)이다. 컨테이너에서 직접 요소를 등록하지는 않는다. 대신에 Registering이라는 이벤트를 발생시킨다. 그럼 등록되어 있는 이벤트 핸들러가 실행된다. Unity 컨테이너에는 기본적으로 UnityDefaultBehaviorExtension의 OnRegister()가 등록되어 있다. 이 핸들러에서 컨테이너에 타입을 등록하는 작업을 해준다. 이런 구조로 가는 것은 바로 사용자 정의가 편해지기 때문이다. 기본적인 거동을 변경하고 싶다면 이 이벤트 핸들러를 재정의해서 등록해주면 되는 것이다.  컨테이너 자체의 코드를 수정하지 않아도 된다. 야튼 각설하고.

■타입의 인스턴스에 접근

다음은 이렇게 등록된 타입의 인스턴스에 대한 참조에 접근하는 방법이다.

stdContainer.Resolve<실제타입>()

익스텐션으로 등록한 타입의 인스턴스를 얻는 방법은 이것과 다르다.

container.Configure<익스텐션타입>()

익스텐션의 경우는 인스턴스를 얻는 메소드가 약간 이상하게 보이기는 하다. 왜 이렇게 이름을 사용했는지 모르겠다.

정리한다고 해 놓고서는 뭘 정리한건지 모르겠네. 쓰으...

근데, 왜 이렇게 타입을 등록하고 등록 정보를 갖는 컨테이너라는 것을 사용하는 것일까? SI 프로젝트에 이 프레임워크를 어떻게 사용할 수 있는가?

SI 프로젝트에는 화면이 매우 많다. 대형 프로젝트인 경우는 몇 천번 페이지 이상이 된다. 이 수천페이지에서는 공통으로 사용하는 모듈이 있다면 이 녀석을 공통으로 등록해 놓고 싶지 않겠는가? 공통 코드를 불러오는 부분이라든가. 사용자 정보를 조회할 수 있는 모듈에 접근하는 부분이라든가. 또는 현재 페이지의 사용자에 대한 권한을 조회할 수 있는 부분 등. 이렇게 공통적인 부분은 <type>에 등록해 놓고 사용하면 좋을 것이다. 그러나 모든 페이지에 대한 타입을 이곳에 등록하는 것은 무리일 것 같다. 페이지에 대한 타입은 이전처럼 메뉴 관리 프로그램에 등록하고 메뉴 조회 모듈을 사용하는 사용하는 것이 바람직할 듯 보인다.

또한 <extension> 부분은 앞에서 말한 사이트별 프레임워크를 만드는 곳으로 적합할 것이라는 생각이다. 앞에서 예로 든 사용자 정보 클래스처럼 사이트별로 별도의 구현을 해야 하는 부분이라든지 하는 부분을 사이트에서 직접 구현해 이곳에 등록해주면 적합할 것 같다.

역시, 뭔가 좀 덧붙여도 여전히 뭘 정리한 건지 모르겠다. 쓰으..

휴일이 또 이렇게 간다.