본문 바로가기

SPRING/Spring

[스프링| 스프링 핵심 원리 | 기본편 | 빈 스코프] 프로토 타입 스코프

정리

여기서 핵심은 스프링 컨테이너는 프로토타입 빈을 생성하고, 의존관계 주입, 초기화까지만 처리한다는 것이다. 클라이 언트에 빈을 반환하고, 이후 스프링 컨테이너는 생성된 프로토타입 빈을 관리하지 않는다. 프로토타입 빈을 관리할 책임은 프로토타입 빈을 받은 클라이언트에 있다. 그래서 `@PreDestroy` 같은 종료 메서드가 호출되지 않는다.

 

public class SingletonTest {

    @Test // JUnit 테스트 메소드임을 선언
    void singletonBeanFind() {

        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SingletonBean.class); // 스프링 컨텍스트를 생성하고, SingletonBean 클래스를 관리 빈으로 등록
        SingletonBean singletonBean1 = ac.getBean(SingletonBean.class); // 컨텍스트에서 SingletonBean 타입의 빈을 요청하여 인스턴스를 얻음
        SingletonBean singletonBean2 = ac.getBean(SingletonBean.class); // 동일한 타입의 빈을 한 번 더 요청하여 인스턴스를 얻음
        System.out.println("singletonBean1 = " + singletonBean1); // 첫 번째로 얻은 빈의 참조를 출력
        System.out.println("singletonBean2 = " + singletonBean2); // 두 번째로 얻은 빈의 참조를 출력
        assertThat(singletonBean1).isSameAs(singletonBean2); // 두 빈의 참조가 같은지 검증

        ac.close(); // 스프링 컨텍스트를 종료
    }

    @Scope("singleton") // 빈이 싱글톤 스코프임을 명시
    static class SingletonBean {

        @PostConstruct // 빈 생성 후 초기화 메소드임을 선언
        public void init() {
            System.out.println("SingletonBean.init"); // 초기화 시 출력될 메시지
        }

        @PreDestroy // 빈 소멸 전 호출될 메소드임을 선언
        public void destroy() {
            System.out.println("SingletonBean.destroy"); // 소멸 시 출력될 메시지
        }
    }
}

싱글톤 스코프는 스프링 프레임워크에서 가장 기본적이며, 가장 널리 사용되는 스코프 중 하나입니다. 싱글톤 스코프에서 스프링 컨테이너는 각 빈 정의에 대해 단 하나의 인스턴스만을 생성하고 관리합니다. 이 인스턴스는 스프링 컨테이너의 생명주기와 연결되어 있으며, 컨테이너가 종료될 때까지 유지됩니다.

싱글톤 스코프의 주요 특징:

  1. 메모리 효율성: 같은 빈에 대해 요청이 여러 번 들어와도 스프링 컨테이너는 이미 생성된 유일한 인스턴스를 반환하기 때문에 메모리 사용량이 절약됩니다.
  2. 공유 상태: 싱글톤 빈은 같은 인스턴스가 애플리케이션의 여러 부분에서 공유되므로 상태 관리에 주의가 필요합니다. 여러 클라이언트가 동일 인스턴스의 상태를 변경할 수 있기 때문에 상태가 없는(stateless) 설계를 권장합니다.
  3. 스프링 설정의 기본값: 별도의 스코프 지정이 없는 경우, 스프링 빈은 기본적으로 싱글톤 스코프로 생성됩니다.

싱글톤 스코프 사용:

싱글톤 스코프를 명시적으로 선언하고자 할 때는 클래스나 메소드에 @Scope("singleton") 어노테이션을 사용합니다. 대부분의 서비스, 리포지터리, 컨트롤러 같은 스프링 관리 컴포넌트는 싱글톤 스코프로 정의되어 애플리케이션 전반에 걸쳐 재사용됩니다.

싱글톤 스코프는 많은 장점을 제공하지만, 애플리케이션의 특정 부분에서 요구되는 독립적인 객체 생명주기 관리가 필요한 경우에는 다른 스코프(예: 프로토타입, 리퀘스트, 세션 스코프 등)를 고려해야 합니다.

 

public class PrototypeTest {

    @Test // JUnit 테스트 메소드임을 선언
    public void prototypeBeanFind() {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(PrototypeBean.class); // 스프링 컨텍스트를 생성하고, PrototypeBean 클래스를 관리 빈으로 등록

        System.out.println("find prototypeBean1"); // 첫 번째 빈 검색 시작을 알림
        PrototypeBean prototypeBean1 = ac.getBean(PrototypeBean.class); // 컨텍스트에서 PrototypeBean 타입의 빈을 요청하여 새로운 인스턴스를 생성
        System.out.println("find prototypeBean2"); // 두 번째 빈 검색 시작을 알림
        PrototypeBean prototypeBean2 = ac.getBean(PrototypeBean.class); // 다시 요청하여 새로운 인스턴스를 생성
        System.out.println("prototypeBean1 = " + prototypeBean1); // 첫 번째로 생성된 빈의 참조를 출력
        System.out.println("prototypeBean2 = " + prototypeBean2); // 두 번째로 생성된 빈의 참조를 출력
        assertThat(prototypeBean1).isNotSameAs(prototypeBean2); // 두 빈의 참조가 다른지 검증

        ac.close(); // 스프링 컨텍스트를 종료
    }

    @Scope("prototype") // 빈이 프로토타입 스코프임을 명시
    static class PrototypeBean {

        @PostConstruct // 빈 생성 후 초기화 메소드임을 선언
        public void init() {
            System.out.println("PrototypeBean.init"); // 초기화 시 출력될 메시지
        }
        @PreDestroy // 빈 소멸 전 호출될 메소드임을 선언 (프로토타입 스코프에서는 일반적으로 호출되지 않음)
        public void destroy() {
            System.out.println("PrototypeBean.destroy"); // 소멸 시 출력될 메시지 (이 코드에서는 실제로 호출되지 않음)
        }
    }
}

프로토타입 스코프는 스프링 프레임워크에서 제공하는 또 다른 유형의 스코프입니다. 이 스코프에서 스프링 컨테이너는 빈을 요청할 때마다 새로운 인스턴스를 생성하여 반환합니다. 이는 싱글톤 스코프와 대조적이며, 각 요청이나 참조마다 독립적인 객체 인스턴스가 필요할 때 사용됩니다.

프로토타입 스코프의 주요 특징:

  1. 독립성: 프로토타입 스코프를 사용하는 빈은 요청할 때마다 새로운 객체가 생성되기 때문에, 생성된 인스턴스 간의 데이터 공유가 없습니다. 각 인스턴스는 독립적으로 작동합니다.
  2. 관리 책임: 프로토타입 스코프의 빈은 스프링 컨테이너에 의해 생성만 되고, 그 이후의 생명주기(예를 들어 소멸)는 스프링 컨테이너에 의해 관리되지 않습니다. 인스턴스의 전체 생명주기 관리는 해당 빈을 사용하는 개발자의 책임입니다.
  3. 사용 사례: 이 스코프는 요청마다 상태를 유지해야 하거나 각 인스턴스가 독립적으로 동작해야 하는 경우에 유용합니다. 예를 들어, 사용자의 요청에 따라 매번 다른 동작을 해야 하는 객체 생성에 적합합니다.

프로토타입 스코프 사용:

프로토타입 스코프를 사용하려면 클래스나 메소드에 @Scope("prototype") 어노테이션을 명시합니다. 이는 스프링 컨테이너에게 해당 빈을 요청할 때마다 새로운 객체를 생성하도록 지시합니다.

프로토타입 스코프는 특정한 사용 사례에 매우 유용하지만, 생성된 각 인스턴스에 대한 참조를 유지하고, 필요에 따라 적절하게 자원을 해제하는 추가적인 관리가 필요합니다. 이는 메모리 누수와 같은 문제를 방지하기 위해 중요합니다.