본문 바로가기
Spring Framework/Spring

[토비의스프링] 1-6 싱글톤 레지스트리와 오브젝트 스코프

by devstep 2022. 3. 30.

싱글톤 레지스트리와 오브젝트 스코프

싱글톤 레지스트리

애플리케이션 컨텍스트는 우리가 만들었던 오브젝트 팩토리와 비슷한 방식으로 동작하는 loC 컨테이너다.
그러면서 동시에 이 애플리케이션 컨텍스트는 싱글톤을 저장하고 관리하는 싱글톤 레지스트리singleton registry이기도 하다.
디자인 패턴에서 나오는 싱글톤 패턴과 비슷한 개념이지만 그 구현 방법은 확연히 다르다.
(영한님 강의 ApplicationContext로 테스트 하는 것이 나왔다고 한다.)

스펙에서 강제하진 않지만, 서블릿은 대부분 멀티스레드 환경에서 싱글톤으로 동작한다.
애플리케이션 안에 제한된 수, 대개 한 개의 오브젝트만 만들어서 사용하는 것이 싱글톤 패턴의 원리다.

싱글톤패턴의 한계

  • private으로 바뀐 생성자는 외부에서 호출할 수가 없기 때문에 DaoFactory에서 UserDao를 생성하며 ConnectionMaker 오브젝트를 넣어주는 게 이제는 불가능해졌다.
  1. private 생성X馮 갖고 있기 때문에 상속할 수 없다
    • 객체지향적인 설계의 장점을 적용하기가 어렵다는 점
  2. 싱글톤은 테스트하기가 힘들다
    • 목(mock) 오브젝트 등으로 대체하기가 힘들다. 싱글톤은 초기화 과정에서 생성자 등을 통해 사용할 오브젝트를 다이내믹하게 주입하기도 힘들기 때문이다.
  3. 서버환경에서는 싱글톤이 하나만 만들어지는 것을 보장하지 못한다
    • 클래스 로더를 어떻게 구성하고 있느냐에 따라서 싱글톤 클래스임에도 하
      나 이상의 오브젝트가 만들어질 수 있다.
    • 여러 개의 JVM에 분산돼서 설치가 되는 경우에도 각각 독립적으로 오브젝트가 생기기 때문에 싱글톤으로서의 가치가떨어진다.
  4. 싱글톤의 사용은 전역 상태를 만들 수 있기 때문에 바람직하지 못하다
    • 싱글톤은 사용하는 클라이언트가 정해져 있지 않다.
    • 애플리케이션 어디서든지 사용될수 있고, 그러다 보면 자연스럽게 전역 상태global state로 사용되기 쉽다.
    • 아무 객체나 자유롭게 접근하고 수정하고 공유할 수 있는 전역 상태를 갖는 것은 객체지향 프로그래밍에서는 권장되지 않는 프로그래밍 모델이다.
    • 그럴 바에는 아예 스태틱 필드와 메소드로만 구성된 클래스를 사용하는 편이낫다.

싱글톤 레지스트리

  • 자바의 기본적인 싱글톤 패턴의 구현 방식은 여러 가지 단점이 있기 때문에, 스프링은 직접 싱글톤 형태의 오브젝트를 만들고 관리하는 기능을 제공한다. 그것이 바로 싱글톤 레지스트리singleton registry다.
  • 평범한 자바 클래스라도 IoC방식의 컨테이너를 사용해서 생성과 관계설정, 사용 등에 대한 제어권을 컨테이너에게 넘기면 손쉽게 싱글톤 방식으로 만들어져 관리되게 할 수 있다. 오브젝트 생성에 관한 모든 권한은 IoC 기능을 제공하는 애플리케이션 컨텍스트에게 있기 때문이다.

싱글톤으로 만들어지기 때문에 주의해야 할 점

  • 상태 관리에 주의를 기울여야 한다.
  • 기본적으로 싱글톤이 멀티스레드 환경에서 서비스 형태의 오브젝트로 시용되는 경우에는 상태정보를 내부에 갖고 있지 않은 무상태stateless 방식으로 만들어져야 한다.
  • 물론 읽기전용의 값이라면 초기화 시점에서 인스턴스 변수에 저장해두고 공유하는 것은 아무 문제가 없다.
public class UserDao {
    private ConnectionMaker connectionMaker; //초기에 설정하면 사용 중에는 바뀌지 않는 읽기전용 인스턴스 변수

    //매번 새로운 값으로 바뀌는 정보를 담은 인스턴스 변수.심각한 문제가 발생한다.
    private Connection c;
    private User user;

    public User get(String id) throws ClassNotFoundException, SQLException {
        this . c = connectionMaker.makeConnection() ;
        this .user = new User();
        this.user.setld(rs.getString("id'));
        this.user.setName(rs.getString('name"));
        this.user.setPassword(rs.getString("password"));
        return this.user;
    }
}
  • 기존에 만들었던 UserDao와 다른 점은 기존에 로컬 변수로 선언하고 사용했던 Connection과 User를 클래스의 인스턴스 필드로 선언했다는 것이다. 따라서 싱글톤으로 만들어져서 멀티스레드 환경에서 사용하면 위에서 설명한 대로 심각한 문제가 발생한다.

스프링 빈의 스코프

  • 스프링이 관리히는 오브젝트, 즉 빈이 생성되고, 존재하고, 적용되는 범위에 대해 알아보자. 스프링에서는 이것을 빈의 스코프scope라고 한다
  • 싱글톤 스코프 : 스프링에서 만들어지는 대부분의 빈은 싱글톤 스코프를 갖는다.
  • 프로토타입 prototype 스코프 : 컨테이너에 빈을 요청할 때마다 매번 새로운 오브젝트를 만들어준다.
  • request 스코프 : 웹을 통해 새로운 HTTP 요청이 생길때마다 생성되는 리퀘스트 스코프
  • 세션session 스코프: 웹의 세션과 스코프가 유사한 세션 스코프

그 외 참고사항

  • 동일성은 == 연산자로.
  • 동등성은 equals( ) 메소드를이용해 비교한다.
  • Object의 equals( ) 메소드는 두 오브젝트의 동일성을 비교해서 그 결과를 들려준다. 따라서 이때는 동일한 오브젝트여야지만 동등한 오브젝트라고 여겨질 것이다.

댓글