posted by 방랑군 2009. 9. 30. 15:21

참조 : http://resisa.tistory.com/53

저번 포스트에 이어서 Spring 컨테이너 대해서 아키텍처와 함께 알아보도록 하겠습니다. 먼저 일반적으로 아키텍처를 구성은 프리젠테이션 레이어(PL) -> 비지니스 로직 레이어(BLL) -> 데이터 액세스 레이어(DAL)로 구성되고 모든 레이어에서는 테이블과 매핑되는 도메인 모델을 참조합니다. 이번 포스트에서는 비지니스 로직 레이어에 해당하는 클래스와 데이터 액세스 레이어에 해당하는 클래스를 만들고 두 레이어 간의 관계를 DI기능과 함께 살펴보도록 하겠습니다.

먼저 DAL에 클래스를 먼저 살펴보겠습니다.

public class DAL

{

    public DAL()

    {

        System.Diagnostics.Debug.WriteLine("데이터 생성자 호출");

    }

 

    ~DAL()

    {

        System.Diagnostics.Debug.WriteLine("데이터 소멸자 호출");

    }

 

    public void ExcuteDal1()

    {

        System.Diagnostics.Debug.WriteLine("데이터 Excute1() 호출");

    }

 

    public void ExcuteDal2()

    {

        System.Diagnostics.Debug.WriteLine("데이터 Excute2() 호출");

    }

 

    public void ExcuteDal3()

    {

        System.Diagnostics.Debug.WriteLine("데이터 Excute3() 호출");

    }

}

=> 생성되는 시점과 소멸되는 시점을 알기 위해서 출력창에 스트링을 찍어줍니다. 그리고 3개의 메소드를 가지고 있습니다. 실질적으로 여기서 DB와 커넥션을 하기 위한 패턴이나 프레임워크를 사용하여야 하는데 이번 포스트의 목적은 아키텍처 관점에서 두 레이어 사이의 관계와 레이어에서 생성되는 객체의 생명주기에 대해서 알아보기 위한 것이므로 생략하였습니다.

그럼 이제 BLL클래스를 만들어 보겠습니다. 2가지 방식으로 BLL 클래스를 만들어 보도록 하겠습니다.
1번째로 DAL클래스를 멤버변수로 가지고 있을 경우입니다.

public class BLL

{

    private DAL dal = new DAL();


    //private DAL dal;

 

    //public DAL Dal

    //{

    //  get { return dal; }

    //  set { dal = value; }

    //}


   
public BLL()

    {

        System.Diagnostics.Debug.WriteLine("비지니스 생성자 호출");

    }

 

    ~BLL()

    {

        System.Diagnostics.Debug.WriteLine("비지니스 소멸자 호출");

    }

 

    public void ExcuteBll1()

    {

        System.Diagnostics.Debug.WriteLine("비지니스 Excute1() 호출");

 

        dal.ExcuteDal1();

        dal.ExcuteDal2();

    }

 

    public void ExcuteBll2()

    {

        System.Diagnostics.Debug.WriteLine("비지니스 Excute2() 호출");

 

        dal.ExcuteDal2();

        dal.ExcuteDal3();

    }

}


2번째로는 BLL클래스의 메소드 안에 DAL클래스를 사용하는 경우입니다.

public class BLL

{

    public BLL()

    {

        System.Diagnostics.Debug.WriteLine("비지니스 생성자 호출");

    }

 

    ~BLL()

    {

        System.Diagnostics.Debug.WriteLine("비지니스 소멸자 호출");

    }

 

    public void ExcuteBll1()

    {

        System.Diagnostics.Debug.WriteLine("비지니스 Excute1() 호출");

       

        DAL dal = new DAL();

        dal.ExcuteDal1();

        dal.ExcuteDal2();

    }

 

    public void ExcuteBll2()

    {

        System.Diagnostics.Debug.WriteLine("비지니스 Excute2() 호출");

 

        DAL dal = new DAL();

        dal.ExcuteDal2();

        dal.ExcuteDal3();

    }

}

=> 1번과 2번에 차이는 무엇일까요? 1번에서는 BLL 객체를 만들면 DAL 클래스의 생성자가 호출이 되고 BLL 클래스의 생성자가 호출됩니다. 2번에서는 BLL 객체를 만들면 BLL 클래스의 생성자만 호출됩니다.
Spring에서 DI의 기능을 사용하기 위한 일반적인 방법은 생성자(Constructor Injection)나 프로퍼티(Setter Injection)를 이용해서 주입시키는 방법으로 바로 1번에 해당하는 구조입니다. 1번 구조로 DI기능을 이용해서 BLL 객체를 만들어보겠습니다. 1번 구조에서 new키워드를 사용한 부분을 제거하고 주석 부분을 해제한 후에 DI기능으로 DAL 객체를 생성해보겠습니다. 아래는 환경설정 파일과 컨테이너에서 BLL 객체를 가져오는 코드입니다.

<object id="dal" type="ObjectLifeCycle.DAL, ObjectLifeCycle" singleton="false"/>

 

<object id="bll" type="ObjectLifeCycle.BLL, ObjectLifeCycle" singleton="false">

  <property name="Dal" ref="dal" />

</object>

IApplicationContext ctx = ContextRegistry.GetContext();

BLL bll = ctx["bll"] as BLL;

 

bll.ExcuteBll1();

//bll.Dal = null;

//GC.Collect();

bll.ExcuteBll2();

=> 컨테이너에서 BLL 객체를 가져올 때와 1번 구조와의 차이점은 BLL과 DAL 객체의 생성시점입니다.
1번 구조에서는  위에서 말했듯이 DAL 생성자가 호출되고 BLL 생성자가 호출됩니다. 반면에 컨테이너에서 BLL 객체를 가져오면 BLL 생성자가 호출이 되고 DI기능에 의해서 DAL 생성자가 호출됩니다. 어느것이 먼저 생성되느냐에 차이점만 있습니다. 처음에 DI기능을 이용하면 프로퍼티를 호출하는 시점에 DAL 객체를 가져오는 줄 알았습니다. 하지만 BLL 객체를 생성한 이후에 바로 DI기능에 의해서 DAL 객체가 생성이 됩니다. 또한 이 구조에서는 DAL객체를 환경설정 파일에서 prototype으로 생성했지만 BLL 객체가 소멸되기 전까지 DAL 객체는 소멸이 되면 안됩니다. 왜냐하면 이전 포스트에서 가비지 수집기에 객체를 수집할 수 있는 방법으로 null을 대입해주는 방법이 있다고 하였고 위의 예에서 주석 부분을 제거하고 실행하면 예외가 발생하기 때문입니다. bll.ExcuteBll2()이 실행되기 직전에 가비지 수집기에 의해 DAL 객체가 소멸되었기 때문입니다.

그렇다면 바로 2번 구조처럼 BLL 클래스에 종속되지 않으면서 필요한 경우에 DAL 객체를 만들어서 사용하는 방법은 없을까요? 그 방법은 바로 메소드(Method Injection)로 주입해주는 방식입니다. 메소드로 주입해주는 방법은 두 가지 있으며 한 가지는 IObjectFactoryAware를 상속받는 방법과 Lookup Method Injection 방법입니다. IObjectFactoryAware 방법은 Spring 문서에서 권장을 하지 않기 때문에 두 번째 방식으로 구현해보겠습니다.
<object id="dal" type="ObjectLifeCycle.DAL, ObjectLifeCycle" singleton="false"/>

 

<object id="bll" type="ObjectLifeCycle.BLL, ObjectLifeCycle" singleton="false">

  <lookup-method name="Dal" object="dal" />

</object>


public abstract class BLL

{

    protected abstract DAL Dal();

 

    public BLL()

    {

        System.Diagnostics.Debug.WriteLine("비지니스 생성자 호출");

    }

 

    ~BLL()

    {

        System.Diagnostics.Debug.WriteLine("비지니스 소멸자 호출");

    }

 

    public void ExcuteBll1()

    {

        System.Diagnostics.Debug.WriteLine("비지니스 Excute1() 호출");

 

        DAL dal = Dal();

        dal.ExcuteDal1();

        dal.ExcuteDal2();

    }

 

    public void ExcuteBll2()

    {

        System.Diagnostics.Debug.WriteLine("비지니스 Excute2() 호출");

 

        DAL dal = Dal();

        dal.ExcuteDal2();

        dal.ExcuteDal3();

    }

}

=> 환경설정 파일에서는 lookup-method란 키워드와 object라는 프로퍼티(ref가 아닙니다)를 사용하고 있음을 볼 수 있고 BLL 클래스에서는 DAL 객체를 얻기 위한 추상 메소드 Dal()과 추상 메소드를 가지기 위해서 BLL 클래스가 추상 클래스로 변경되었습니다. 그리고 이전처럼 Spring 컨테이너에서 BLL 객체를 생성하고 BLL 객체의 메소드를 실행하면 DAL 객체가 메소드마다 각각 생성되는 것을 확인하실 수 있습니다. 이외에 예제 코드를 이용해서 BLL과 DAL클래스를 singleton과 prototype으로 번갈아 가면서 설정해서 실행해보면 실제로 객체들이 언제 만들어지고 언제 사라지는지를 알 수 있습니다. 또한 Spring에서 제공해주는 AdoTemplate를 singleton으로 생성할 때의 DB커넥션 문제라던지 lookup-method방식에의 추상클래스로 인한 TDD코드 작성시에 혹 나타날 문제점이라던지 추상클래스를 Base클래스로 사용하면서 아키텍처를 구성해보는 방법 등등 여러가지 테스트가 더 필요할 것 같습니다.

2번에 걸쳐 객체의 생명주기에 대해서 알아보았습니다. 객체에 생명주기에 관심이 없으신 분들은 객체 하나 만드는데 너무 복잡한거 아니냐 가비지 수집기가 있는데 왜 그런거에 관심을 가져야 하느냐 반문 하실 수 있습니다. 하지만 진짜 프로그래머라면 어떻게 하면 좀 더 효율적으로 프로그래밍을 할 것인가에 대한 고민은 밥을 먹는것과 같은거 아닐까요?

'GET > FrameWork' 카테고리의 다른 글

방랑이가 생각하는 Spring.NET...  (0) 2009.10.06
Spring.NET - 레퍼런스 문서 한글화 사이트..  (0) 2009.09.30
객체의 생명주기  (0) 2009.09.30
Spring.NET 생명 주기  (0) 2009.09.30
Hands-on Labs for EL 4.1 and Unity 1.2  (0) 2009.09.29