말그대로 빈이 사용되어지는 범위(?)인데, 빈이 앱이 구동되는 동안 한개만 만들어서 쓸 것인지 HTTP요청마다 생성해서 쓸 것인지 등등를 결정하는 것이 스코프임.
보통의 스프링 빈은 스프링 앱이 구동 될때 한번에 ApplicationContext에서 한 번에 모두 생성해서 하나의 클래스는 한 개의 빈만 가지지만 (Singleton), 때에 따라서는 HTTP요청마다 (Request) 다른 빈을 생성해서 쓸건지, 매번 사용될 때 마다 (Prototype) 빈을 생성해서 쓸건지 설정해서 쓸 수도 있다.
링크
spring docs에서 가져온 건데 불친절하게 해석하자면,,,,
Scope | Description |
---|---|
singleton | (기본값) 스프링 IoC 컨테이너당 하나의 인스턴스만 사용 - 한마디로 앱이 구동되는 동안 하나만 쓴다는 거임 |
prototype | 매번 새로운 빈을 정의해서 사용 |
request | HTTP라이프 사이클 마다 한개의 빈을 사용, web-aware 컨택스트에서만 사용가능 - ex. Applicaiton context |
session | HTTP 세션마다 하나의 빈을 사용, web-aware 컨택스트에서만 사용가능 - ex. Applicaiton context |
application | ServeltContext라이프사이클 동안 한개의 빈만 사용, web-aware 컨택스트에서만 사용가능 - ex. Applicaiton context |
websocket | websocket 라이프사이클 안에서 한개의 빈만 사용, web-aware 컨택스트에서만 사용가능 - ex. Applicaiton context |
@Component
@Scope(value = "prototype")
public class ProtoType {
}
바로 컴포넌트로 등록 하면서, @Scope를 붙여주면 된다. value의 값으로는 위에서 언급한 값이 Scope이름이 String으로 들어가게 되는데...
바로 Sinlgeton 스코프의 빈이 prototype의 빈을 주입받는 경우임
말로하면 이해가 안가니까 직관적으로 코드로 보자면
@Component
public class Single {
@Autowired
ProtoType protoType;
public ProtoType getProtoType() {
}
}
@Component
@Scope(value = "prototype")
public class ProtoType {
}
코드에서 보는 것 과 같이 싱글톤 스코프의 빈이 프로토타입 빈을 주입받으면 싱글톤의 프로토타입 빈은 매번 바뀌지 않고 같은 빈이 쓰임
@Component
public class AppRunner implements ApplicationRunner {
@Autowired
Single single;
@Autowired
ProtoType protoType;
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("---singleton---");
System.out.println(context.getBean(protoType.getClass()));
System.out.println(context.getBean(protoType.getClass()));
System.out.println(context.getBean(protoType.getClass()));
System.out.println("---prototype---");
System.out.println(single);
System.out.println(single);
System.out.println(single);
System.out.println("---prototype by singleton---");
System.out.println(single.getProtoType());
System.out.println(single.getProtoType());
System.out.println(single.getProtoType());
}
}
이렇게 프로토타입이지만 매번 같은 빈을 사용함
singleton 빈은 ApplicationContext가 처음 앱을 구동할때 빈을 만들고 빈을 주입해서 앱이 종료될 때 까지 계속 사용 되기 때문에 singleton 빈 안에 있는 prototype 빈도 처음 주입된 채로 그대로 사용된다.
두가지 방법이 있는데,,,
1. proxy mode를 이용하는 방법
@Component
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class ProtoType {
}
프로토타입으로 쓸 빈에 @Scope 어노태이션에 proxyMode = ScopedProxyMode.TARGET_CLASS를 넣어주면 된다. 만약에 해당 오브잭트가 클래스가 아니라 인터페이스라면 proxyMode = ScopedProxyMode.INTERFACES도 쓸 수가 있다.
2. ObjectProvider객체를 사용하는 방법
@Component
public class Single {
@Autowired
ObjectProvider<ProtoType> protoType;
public ProtoType getProtoType() {
return protoType.getIfAvailable();
}
}
ObjectProvider< >를 용해서 매번 빈을 주입하는 방법 도 있다. 하지만,
1번이 POJO를 유지하기 때문에 기선이형은 프록시모드를 이용한 방법을 추천해 줬음!
proxy mode가 어떻게 작동하는지 간단하게 설명하자면,
그림에서 처럼 ApplicationConxtext가 빈을 처음에 생성할 때 proto 빈을 주입받는게 아니라 proto 클래스를 상속받은(타입이 같은) proxy클래스를 만들어서 빈으로 등록하고 proxy클래스에서 내부적으로 매번 새로운 proto빈을 사용하게 끔 설계 되어있다.