Spring Ch 1. IoC 컨테이너(3) - 빈의 스코프


빈의 스코프

싱글톤

  • 애플리케이션 전반에 걸쳐 빈의 인스턴스가 오직 하나만 존재한다.
  • Autowired에 의해 주입된 싱글톤 객체는 다른 객체에 주입된 싱글톤 객체와 동일한 객체이다.

프로토타입

  • @Scope(“prototype”)으로 프로토타입을 선언한다.
  • 프로토타입 객체는 매 호출마다 객체가 초기화된다.
1
2
3
4
5
6
7
@Component 
@Scope("prototype") //@Scope 어노테이션으로 빈의 스코프를 지정할 수 있다.
public class Proto {
}
@Component
public class Single {
}

※싱글톤 빈에서의 프로토타입 빈 참조

  • 프로토타입 빈에서 싱글톤 빈을 참조하려는 경우 주입 받는 싱글톤 빈 객체는 모두 동일한 객체이다.
  • 그러나 싱글톤 빈에서 프로토타입 빈을 참조하려는 경우 프로토타입 객체는 싱글톤 빈이 한번만 초기화되기 때문에 다수의 호출에도 초기화가 이루어지지 않는다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
@Component 
@Scope("prototype")
//@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class Proto {
@Autowired
private Single single;
public Single getSingle() {
return single;
}
}
@Component
public class Single {
@Autowired
private Proto proto;
public Proto getProto() {
return proto;
}
}
@Component
public class AppRunner implements ApplicationRunner{
@Autowired
Single single;
@Autowired
Proto proto;
@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));

System.out.println("Proto_single");
//singleton bean이므로 동일한 객체이다.
System.out.println(ctx.getBean(Proto.class).getSingle());
System.out.println(ctx.getBean(Proto.class).getSingle());
System.out.println(ctx.getBean(Proto.class).getSingle());

System.out.println("Single_proto");
//protype bean이지만 변경되지 않았다!
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.TARGET_CLASS로 하여 해결할 수 있다.
  • ProxyMode는 Prototype 클래스를 Proxy Instance로 감싸 인스턴스를 참조하도록 한다.
  • 싱글톤 빈에서 prototype 객체를 호출할 때 Proxy 객체가 호출되고, Proxy 객체 내부의 Prototype 객체를 호출하기 때문에 초기화가 이루어진다.
1
2
3
4
@Component 
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class Proto {
}

댓글