일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- GC로그수집
- deque
- map
- date
- javascript
- Calendar
- dfs
- 스택
- NIO
- Properties
- 리소스모니터링
- Union-find
- priority_queue
- set
- math
- string
- BFS
- alter
- JPA
- sql
- 큐
- scanner
- union_find
- spring boot
- 힙덤프
- 스프링부트
- CSS
- List
- html
- Java
- Today
- Total
매일 조금씩
[IoC 컨테이너와 빈] 5. 빈의 스코프 본문
[전체 목차]
- IoC 컨테이너와 빈
- 스프링 IoC 컨테이너와 빈
- ApplicationContext와 다양한 빈 설정 방법
- @Autowired
- @Component와 컴포넌트 스캔
- 빈의 스코프
- Resource / Validation
- 데이터 바인딩
- SpEL
- 스프링 AOP
- Null-Safety
1. 스코프
우리가 지금까지 등록한 모든 빈들은 사실상 스코프라는게 있다.
그 중에서도 싱글톤 스코프의 빈들만 사용해왔다.
왜냐면 아무런 설정도 하지 않으면 Spring에서 기본 설정이 싱글톤 스코프이기 때문이다.
1) 싱글톤
싱글톤 스코프란?
=> 애플리케이션 전반에서 해당 빈의 인스턴스가 오직 한개뿐인게 싱글톤 스코프다.
거의 대부분의 경우에 싱글톤 스코프를 쓸거다.
2) 프로토타입
- Request
- Session
- Websocket
- ...
프로토타입이라는 스코프는 매번 새로운 인스턴스를 만들어서 써야하는 거다.
그런 스코프의 경우엔 아래 예시처럼 @Scope
를 사용해서 직접 원하는 스코프를 써주면 된다.
Enum이라도 추가해주면 좋은데.. 그게 없어서 스트링을 직접 쳐야함.
이러면 프로토타입 빈이기 때문에 해당 빈을 받아 올때마다 새로운 인스턴스가 생성된다.
예를들어,
applicationContext.getBean(RoomService.class);
를 할때마다 새로운 인스턴스를 생성해서 가져온다.
2. 프로토타입 빈이 싱글톤 빈을 참조하면?
프로토타입의 빈이 싱글톤 스코프의 빈을 참조해서(주입받아서) 쓰면 아무 문제가 없다.
프로토타입 빈은 계속 바뀌지만, 내부의 싱글톤 스코프의 빈은 계속 재활용 되어 하나여서 두개 다 의도된대로 동작하기 때문이다.
3. 싱글톤 빈이 프로토타입 빈을 참조하면?
1) 프로토타입 빈이 업데이트가 안되네?
근데 반대로, 싱글톤 스코프의 빈이 프로토타입의 빈을 참조해서 쓰면 문제가 생긴다.
왜냐하면, 싱글톤 스코프는 변하지 않기때문에 주입받을 때의 그 빈을 계속 가져다가 쓴다.
따라서 아래처럼,
applicationContext.getBean(Single.class).getProto();
이러한 방식으로 Proto 빈을 가져오면 의도한 것은 매번 다른 빈을 가져오는 거지만, 매번 같은 빈을 가져오게 된다.
2) 업데이트 하려면?
2-1) scoped-proxy
이걸 해결하는 방법 중, 이해해보려하면 어렵지만 적용하기에 가장 쉬운 방법은,
proxy모드를 설정해주는 것이다.
위 예시는 해당 클래스가 인터페이스가 아닌 클래스라서 프록시 모드는 TARGET_CLASS
로 설정했다.
이렇게 TARGET_CLASS
를 사용하면 CGlib를 사용한 다이나믹 프록시가 적용이 된다.
이게 무슨말이냐 하면..
프로토 타입으로 정의한 해당 클래스 빈을 프록시 기반으로 감싸서,
다른 빈들이 해당 빈을 가져다 쓸 때, 프록시로 감싸진 빈을 가져다 쓰라는 말이다.
왜냐면, 다른 빈들이 이 프로토타입 스코프의 빈을 직접 참조하면 안되기 때문이다.
그래서 프록시를 거쳐서 참조하도록 해야한다.
왜 직접 참조하면 안되냐? 직접 쓰면 바꿔줄 여지가 없기 때문이다.
원래 자바 기반의 JDK 안에 있는 다이나믹 프록시는 인터페이스의 프록시 밖에 못 만든다..ㅜㅜ
그래서 기존 프로토타입의 클래스를 상속받은 클래스로 프록시를 만들어주는 CGlib 라는 3rd party의 라이브러리가 있다.
이 CGlib는 클래스도 프록시를 만들 수 있게 한다.
그래서 위 예시 코드에 추가된 proxyMode = ScopedProxyMode.TARGET_CLASS
옵션은 어떤 모드로 만들건지,
즉, CGlib 기반의 클래스를 상속받은 (클래스 기반의) 프록시를 만들도록 언급해 준 것이다.
만약, 프로토타입의 클래스가 인터페이스였다면 TARGET_CLASS
가 아닌 INTERFACE
도 쓸수 있다.
그러면 JDK에 있는 인터페이스 기반의 프록시를 만들어서 썼을 거다.
프록시 인스턴스가 빈으로 등록이 되고, 프록시 빈이 존재하는 기존 빈은 주입될 때 프록시 빈으로 주입이 된다.
이 프록시에 대해선 AOPA 에서 더 자세하게 다루게 된다.
2-2) Object-Provider
이 프록시가 성능에 영향을 줄거같아서 꺼려진다 하면 다른 방법도 있다.
프로토 타입 빈을 주입받는 클래스에서 다음과 같이 ObjectProvider
로 감싸도록 코드를 변경해주면 된다.
@Component
public class Single {
@Autowired
private ObjectProvider<Proto> proto;
public Proto getProto() {
return proto.getIfAvailable();
}
}
그러나 ObjectProvider
는 Spring에서 제공하는 거고, 코드 자체에 Spring코드가 들어가버려서 딱히 추천하진 않는다.
그래서 위의 프록시를 사용한 방법처럼 빈을 생성할때만 Spring 관련된 스코프 프로필을 쓰는게 낫다.
그렇게 해서 코드는 완전 POJO스럽게 유지하는게 낫다.
대부분의 상황에선 싱글톤만 써서 걱정안해도 되지만,
롱런 하는(싱글톤) 빈이 짧은 생명주기를 가지는 빈들을 주입 받을 때, 위 방법들로 해결하면 된다.
4. 싱글톤 객체 사용 시 주의할 점
- 프로퍼티가 공유 (멀티스레드 환경에서 Thread-safe 보장 x)
- ApplicationContext 초기 구동 시 인스턴스 생성 (초기 구동시 시간이 더 소요될수 있음)
'Spring Framework > 스프링 프레임워크 핵심 기술' 카테고리의 다른 글
[IoC 컨테이너와 빈] 4. @Component 와 컴포넌트 스캔 (1) | 2024.11.04 |
---|---|
[IoC 컨테이너와 빈] 3. @Autowired (0) | 2024.11.03 |
[IoC 컨테이너와 빈] 2. ApplicationContext와 다양한 빈 설정 방법 (0) | 2024.11.03 |
[IoC 컨테이너와 빈] 1. 스프링 IoC 컨테이너와 빈 (0) | 2024.11.03 |