✔ Inflearn 강의 수강 내용 정리글입니다!
스프링 빈이 존재할 수 있는 범위
빈 스코프는 다음과 같은 방식으로 지정 가능하다. 위는 컴포넌트 스캔 자동 등록, 아래는 수동 등록이다.
@Scope("prototype")
@Component
public class HelloBean {}
@Scope("prototype")
@Bean
PrototypeBean HelloBean() {
return new HelloBean();
}
프로토타입 스코프를 스프링 컨테이너에서 조회하면 같은 인스턴스를 반환하는 싱글톤 스코프 빈과 달리 항상 새로운 인스턴스를 생성하여 반환한다.
스프링 컨테이너는 프로토타입 빈을 생성하고, 의존관계를 주입하고, 초기화까지만 처리!
클라이언트에 빈을 반환한 후에 스프링 컨테이너는 프로토타입 스코프 빈을 관리하지 않는다.
➡@PreDestroy
같은 종료 메서드는 호출되지 않는다.
ClientBean은 싱글톤 빈이므로 스프링 컨테이너 생성 시점에 함께 생성되고 PtoyotypeBean을 주입받는다.
ClientBean은 싱글톤 빈이므로 서로 다른 클라이언트 A, B가 요청할 때마다 항상 같은 ClientBean이 반환된다.
ClientBean이 가지고 있는 PrototypeBean은 이미 과거제 주입이 끝난 빈!
싱글톤 빈은 생성 시점에만 의존관계를 주입받기 때문에 서로 다른 클라이언트가 ClientBean을 요청한다고 해도 요청할 때마다 프로토타입 빈이 생성되는 것이 아니다.
➡ 프로토타입 빈을 주입 시점에만 새로 생성하는 것이 아니라, 사용할 때마다 새로 생성해서 사용하고자 한다면?
싱글톤 빈과 프로토타입 빈을 함께 사용할 때, 사용할 때마다 새로운 프로토타입 빈을 생성하고싶다!
스프링 컨테이너게 직접 프로토타입 빈을 요청하여 새로운 프로토타입 빈을 반환받는 것도 방법이다.
public int logic() {
PrototypeBean prototypeBean = ac.getBean(PrototypeBean.class);
prototypeBean.addCount();
int count = prototypeBean.getCount();
return count;
}
ac.getBean()
을 통해 항상 새로운 프로토타입 빈이 생성되고 반환된다.ObjectProvider
: 지정한 빈을 컨테이너에서 대신 찾아주는 DL 서비스 제공
public int logic() {
PrototypeBean prototypeBean = prototypeBeanProvider.getObject();
prototypeBean.addCount();
int count = prototypeBean.getCount();
return count;
}
prototypeBeanProvider.getObject()
을 통해 항상 새로운 프로토타입 빈 생성ObjectProvider
: 필요한 DL 기능만 제공!ObjectFactory : 기능 단순, 별도 라이브러리 필요 ❌, 스프링에 의존
ObjectProvider : ObjectFactory 상속, 옵션, 스트림 처리 등 편의 기능이 많고, 별도 라이브러리 필요 ❌, 스프링에 의존
동시에 여러 HTTP 요청이 오면 어떤 요청이 남긴 로그인지 구별하지 어렵다 ➡ 이때 사용하기 좋은 것이 request 스코프!
@Component
@Scope(value = "request")
public class MyLogger {
private String uuid;
private String requestURL;
public void setRequestURL(String requestURL) {
this.requestURL = requestURL;
}
public void log(String message) {
}
@PostConstruct
public void init() {
}
@PreDestroy
public void close() {
}
}
Controller와 Service를 설계한 후 애플리케이션 실행했을 때 시점에 다음과 같은 오류 발생
스프링 애플리케이션을 실행하는 시점에 싱글톤 빈은 생성해서 주입이 가능하지만, request 스코프 빈은 실제 고객의 요청이 와야 생성되므로 아직 생성되지 않는다.
Provider를 통해 문제 해결 가능!
private final ObjectProvider<MyLogger> myLoggerProvider;
MyLogger myLogger = myLoggerProvider.getObject();
myLogger.setRequestURL(requestURL);
ObjectProvider.getObject()
를 호출하는 시점까지 request scope빈의 생성을 지연@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyLogger {
}
핵심은 proxyMode = ScopedProxyMode.TARGET_CLASS
private final MyLogger myLogger;
myLogger.setRequestURL(requestURL);
myLogger = class hello.core.common.MyLogger$$EnhancerBySpringCGLIB$$b68b726d
진짜 MyLogger를 찾는 방법을 알고있다.
📍 진짜 객체 조회를 꼭 필요한 시점까지 지연처리!
[출처 - Inflearn : 스프링 핵심 원리 - 기본편]
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard