본문 바로가기
Spring/Spring Core

[Section 1] IoC 컨테이너 5부: 빈의 스코프(Scope)

by kevinntech 2020. 9. 3.

해당 게시물은 백기선님의 스프링 프레임워크 핵심 기술 강좌를 정리한 내용 입니다.

 

1. 빈의 범위(Scope) 

 

싱글톤해당 Bean의 인스턴스를 단 한번만 생성한다. (기본 값)

 

- 프로토타입은 해당 Bean의 인스턴스를 매번 새롭게 생성한다. 

 

  프로토타입과 유사한 Scope는 Request, Session, WebSocket 등이 있다.

 

2. 빈의 범위(Scope) 관련 실습

 

      빈의 Scope에 대해서 알아보기 위해 다음과 같은 실습을 진행 한다.

 

      Proto라는 클래스를 작성하고 Bean으로 등록 한다.

 

      그리고 @Scope를 붙여서 prototype으로 지정 한다.

 

@Component
@Scope("prototype")
public class Proto {
}

 

      Single이라는 클래스를 작성한 다음, Bean으로 등록하고 Proto 타입의 필드에 의존성을 주입 받는다.

 

      그리고 Single 클래스의 proto 값을 가져 올 수 있도록 getter를 작성한다.

 

@Component
public class Single {

    @Autowired
    private Proto proto;

    public Proto getProto() { // Single이 참조하고 있는 Proto를 반환
        return proto;
    }
}

 

      AppRunner 클래스에서 ApplicationContext를 이용하여 getBean()의 내용을 출력 해보면

 

      싱글톤의 스코프인 Single 빈은 항상 같은 인스턴스이며 프로토타입의 스코프인 Proto 빈은 매번 새로운 인스턴스를 생성하는 것을 확인

 

      할 수 있다.

 

@Component
public class AppRunner implements ApplicationRunner {

    @Autowired
    ApplicationContext ctx;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("proto");

        System.out.println(ctx.getBean(Proto.class));
        System.out.println(ctx.getBean(Proto.class));
        System.out.println(ctx.getBean(Proto.class));

        System.out.println("single");
        System.out.println(ctx.getBean(Single.class));
        System.out.println(ctx.getBean(Single.class));
        System.out.println(ctx.getBean(Single.class));
    }
}

 

3. 싱글톤과 프로토타입을 같이 사용 하는 경우, 발생할 수 있는 문제점

 

      ① 프로토타입 빈이 싱글톤 빈을 참조하는 경우

 

            →  아무 문제가 없다.

 

                   그 이유는 프로토타입의 Bean은 Ioc 컨테이너에서 매번  꺼낼 때 마다 항상 새로운 인스턴스를 생성하지만

                   그 새로운 인스턴스가 참조하고 있는 싱글톤 Bean은 항상 동일하며 원래 의도한대로 사용되는 것이므로

                   문제가 없다.

 

@Component
@Scope("prototype")
public class Proto {

    @Autowired
    Single single;
}

 

      싱글톤 빈이 프로토타입 빈을 참조하는 경우 

 

             →  문제가 발생 함

 

                   싱글톤 Bean은 인스턴스가 단 한번만 생성 된다.
                   그리고 생성될 때 프로토타입 Bean의 프로퍼티도 이미 설정 되었기 때문에
                   매번 싱글톤 Bean을 사용할 때, 프로토타입 빈의 프로퍼티가 변경되지 않는 문제점이 있다.

 

                   * 여기서 언급되는 프로퍼티는 필드(field)와 같은 의미

 

@Component
public class AppRunner implements ApplicationRunner {

    @Autowired
    ApplicationContext ctx;

    @Override
    public void run(ApplicationArguments args) throws Exception {

        System.out.println("proto by single");

        /* 여기서 getProto()가 매번 다른 인스턴스를 반환하는 것을 의도 하였는데
           결과는 그렇지 않음 */
        System.out.println(ctx.getBean(Single.class).getProto());
        System.out.println(ctx.getBean(Single.class).getProto());
        System.out.println(ctx.getBean(Single.class).getProto());
    }
}

 

 

      앞서 살펴본 문제점을 해결하는 방법은 @Scope 애노테이션을 사용할 때 proxyMode를 설정하는 것이다.

      (scopedProxyMode.DEFAULT가 기본 값이며  이는 Proxy를 사용하지 않는다는 것을 의미한다.)

 

      proxyMode = scopedProxyMode.TARGET_CLASS


      해당 Bean을 클래스 기반의 Proxy로 감싸도록 한다.         

 

      Proxy로 감싸는 이유는 무엇일까?

 

      싱글톤 Bean이 프로토타입 Bean을 직접 참조하는 것이 아닌 Proxy를 거쳐서 참조 하도록 해야

      프로토타입 Bean을 매번 새로운 인스턴스로 바꿔 줄 수 있다.

 

@Component 
@Scope(value = "prototype", proxyMode = scopedProxyMode.TARGET_CLASS)
public class proto {

}

 

 

 

4. 싱글톤 객체 사용 시 주의할 점

 

- 프로퍼티(필드)가 공유 되므로 thread-safe 할 것이라고 보장 받을 수 없음

   그러므로 thread-safe한 방법으로 코딩 해야 한다.

 

- 싱글톤 객체는 ApplicationContext 초기 구동 시 생성하게 된다.

 

댓글