UpDown Dev Story
빈 스코프란 본문
1. Bean 스코프
빈 스코프는 무엇인가?
말그대로 빈이 사용되어지는 범위(?)인데, 빈이 앱이 구동되는 동안 한개만 만들어서 쓸 것인지 HTTP요청마다 생성해서 쓸 것인지 등등를 결정하는 것이 스코프임.
보통의 스프링 빈은 스프링 앱이 구동 될때 한번에 ApplicationContext에서 한 번에 모두 생성해서 하나의 클래스는 한 개의 빈만 가지지만 (Singleton), 때에 따라서는 HTTP요청마다 (Request) 다른 빈을 생성해서 쓸건지, 매번 사용될 때 마다 (Prototype) 빈을 생성해서 쓸건지 설정해서 쓸 수도 있다.
빈 스코프의 종류는??
링크
spring docs에서 가져온 건데 불친절하게 해석하자면,,,,
ScopeDescription
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 |
2. ProtoType 스코프를 사용하는 방법
그렇다면 스프링 빈 스코프를 어떻게 정의하고 사용할 수 있을까?
@Component
@Scope(value = "prototype")
public class ProtoType {
}
바로 컴포넌트로 등록 하면서, @Scope를 붙여주면 된다. value의 값으로는 위에서 언급한 값이 Scope이름이 String으로 들어가게 되는데...
- @Scope(value = "prototype")
- @Scope(value = "singleton")
- @Scope(value = "request")
- @Scope(value = "session")
- @Scope(value = "application")
- @Scope(value = "websocket")
이렇게 쓰면 된다
하지만 , 문제가 발생하는 경우가 있음...
바로 Sinlgeton 스코프의 빈이 prototype의 빈을 주입받는 경우임
말로하면 이해가 안가니까 직관적으로 코드로 보자면
@Component
public class Single {
@Autowired
ProtoType protoType;
public ProtoType getProtoType() {
}
}
코드에서 보는 것 과 같이 싱글톤 스코프의 빈이 프로토타입 빈을 주입받으면 싱글톤의 프로토타입 빈은 매번 바뀌지 않고 같은 빈이 쓰임
@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를 유지하기 때문에 기선이형은 프록시모드를 이용한 방법을 추천해 줬음!
3. Outro
proxy mode가 어떻게 작동하는지 간단하게 설명하자면,
그림에서 처럼 ApplicationConxtext가 빈을 처음에 생성할 때 proto 빈을 주입받는게 아니라 proto 클래스를 상속받은(타입이 같은) proxy클래스를 만들어서 빈으로 등록하고 proxy클래스에서 내부적으로 매번 새로운 proto빈을 사용하게 끔 설계 되어있다.
'Spring' 카테고리의 다른 글
Spring Bean의 정의와 여러가지 등록방법 (0) | 2021.05.21 |
---|---|
스프링 컨테이너의 정의와 종류 (0) | 2021.05.20 |
좋은 객체 지향 설계의 5가지 원칙(SOLID) (0) | 2021.05.20 |
Spring Framework 의 정의와 특징 (0) | 2021.05.20 |
Spring Batch 시작하기 (Spring Boot) - JOB 생성 (0) | 2020.01.30 |