2012. 2. 22.

ApplicationContext 동작방식



Singleton Registry

Spring의 Application Context는 기본적으로 bean 생성에 있어 다음과 같이 동작한다.


Spring 은 디폴트로 내부에서 생성하는 Bean object 를 singleton으로 만든다.
이것은 디자인 패턴의 싱글톤과 비슷한 개념이지만, java 의 일반 구현방법은 확연히 다르다.(참고: Singleton Pattern)
즉, Spring container 에서 object 를 singleton registry 에 관리하며 singleton으로 동작하도록 제어한다.
Spring의 ApplicationContext 는 Singleton을 저장하고 관리하는 Singleton registry 이다.



* 왜 Spring 은 default로 bean을 singleton 으로 생성할까?



하나의 요청(Request)를 처리하기 위해서는 데이타 액세스 로직(DAO), 서비스 로직, 비즈니스 로직, 프리젠테이션 로직등 다양한 기능을 담당하는 오브젝트들이 계층형 구조로 이루어 진다. 매번 클라이언트 요청이 올때마다, 각 로직을 담당하는 오브젝트들을 새로 만들어 사용한다면, 아무리 Java가 오브젝트 생성과 GC(Garbage Collection) 성능이 좋아졌어도 서버가 부하를 감당하기 심들다. 이 때문에 엔터프라이즈 분야에서는 서비스오브젝트 라는 개념을 사용해 왔는데 Servlet 은 Java 엔터프라이즈 기술의 가장 기본이 되는 서비스 오브젝트라고 할수 있다. Servlet은 대부분 멀티스레드 환경에서 Singleton으로 동작한다. 즉, Servlet 클래스 당 하나의 오브젝트만 만들어 주고, 사용자의 요청을 담당하는 여러 스레드에서 하나의 오브젝트를 공유해서 사용한다.

* Singleton registry 덕분에 singleton 으로 동작해야 할 어떤 클래스라도 평범한 java class 로 작성될 수 있다. 즉, public 생성자를 가질 수 있으며 static method 를 노출할 필요도 없다. 이것은 테스트 환경에서 자유롭게 object 를 만들 수 있고 또한 OOP의 장점을 그대로 가진다.


* Spring 에서 Singleton object 로 사용할 클래스 설계시 주의점

Spring 에서 singleton 이 멀티스레드 환경에서 서비스 오브젝트에 사용되는 경우에는 상태정보를 내부에 갖고 있지 않은 stateless 로 만들어야 한다. 이 경우, 각 요청에 대한 정보나 생성된 정보는 메소드 파라미터나 메소드 안의 로컬변수 혹은 리턴값 등으로 처리해야 한다. 싱글톤이라해도 메소드 안에서 생성되는 로컬변수는 method가 호출될 때마다 매번 새로 할당되므로 싱글톤이라 해도 여러 스레드가 변수의 값을 덮어쓸 일은 없다.

public class UserDao {
  private ConnectionMaker connectionMaker; <-- (1)
  private Connection c;  <-- (2)
  private User user;       <-- (2)

  public User get(String id) throws ClassNotFoundException, SQLException {
    this.c = connectionMaker.makeConnection();
    ....
    this.user = new User();
    this.user.setId("...");
    ...
    return user;
  } 
}

UserDao 는 IoC container 에 의해서 singleton object 로 생성/사용된다고 가정해 보자.
이런 경우, (2)번과 같이 멀티스레드 환경에서 변경될 수 있는 값을 클래스의 인스턴스 변수로 생성하는 경우, 문제가 발생한다. 따라서 Spring 의 singleton bean 으로 사용되는 클래스를 만들때는 (2)번의 경우는 method 내 로컬 변수로 사용하거나 파라미터로 주고 받으며 사용해야 한다.

단, 이 경우에도 클래스 인스턴스 변수로 사용가능한 경우가 있는데 이는 (1) 과 같다.
(1)은 자신이 사용하는 다른 singleton bean 을 저장하려는 용도라면, 인스턴스 변수로 사용해도 좋다. 스프링이 초기화 되고 나면, 이후에 수정되지 않는 경우라면, 멀티스레딩 환경에서 사용해도 문제없다


* Spring bean 의 Scope

scope : 스프링이 관리하는 오브젝트, 즉 빈의 생성/존재/소멸되는 범위

- singleton : 스프링 bean 의 기본 scope 는 singleton 이다. 컨테이너 한개에 한개만 생성되며 강제로 제거하지 않는 한 컨테이너가 존재하는 동안 계속 유지된다.
- prototype : 컨테이너에 빈을 요청할 때마다 매번 새로운 오브젝트를 만들어준다.
- request : 웹을 통해 HTTP 요청시마다 생성되는 scope
- session : 웹의 세션과 유사한 scope



댓글 1개: