스프링 컨테이너 생성 → 스프링 빈 생성 → 의존관계 주입 → 초기화 콜백 → 사용 → 소멸 전 콜백 → 스프링 종료
스프링 컨테이너는 스프링 빈을 생성하는 동시에 해당 빈에 존재하는 모든 의존관계를 주입한다. 이 과정이 종료되면 초기화 작업이 시작되는데, 스프링에서는 초기화 시점에 호출할 수 있는 콜백 메서드를 제공한다. 또한, 비슷한 맥락에서 스프링 빈이 소멸되기 직전에 호출 가능한 콜백 메서드도 제공한다.
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class NetworkClient implements InitializingBean, DisposableBean {
...
@Override
public void afterPropertiesSet() throws Exception {
// 초기화 시점에 실행되는 메서드
}
@Override
public void destroy() throws Exception {
// 소멸 시점에 실행되는 메서드
}
}
InitializingBean, DisposableBean은 스프링에서 제공하는 인터페이스로, 실제 사용하고자 하는 클래스에 implements하여 사용하면 된다.
인터페이스 단점
다음과 같은 단점 때문에 현재는 잘 사용하지 않는 방법이다.
빈 등록 시 설정 정보에 메서드 이름을 지정하는 방법이다. 다음과 같은 문법으로 사용할 수 있다.
- 초기화, 소멸 메서드 작성
public void init() throws Exception {
// 초기화 시점에 실행되는 메서드 작성
}
public void close() throws Exception {
// 소멸 직전에 실행되는 메서드 작성
}
- 빈 등록 시 해당 메서드 지정
@Configuration
static class LifeCycleConfig {
@Bean(initMethod = "init", destroyMethod = "close")
public NetworkClient networkClient() {
// 생성자
}
}
설정 정보 단점
종료메서드(destroyMethod) 추론 기능
스프링에서 공식적으로 권장하는 방법이다. 이렇게 등록만 해주면 다른 코드는 고칠 필요 없이 적용된다.
@PostConstruct
public void init() throws Exception {
// 초기화 시점에 실행되는 메서드
}
@PreDestroy
public void close() throws Exception {
// 소멸 직전에 실행되는 메서드
}
스프링에 종속적인 기술이 아니라 JSR-250 라는 자바 표준이다. 따라서 스프링이 아닌 다른 컨테이너에서도 동작한다.
프로토타입 빈을 스프링 컨테이너에 요청하면 컨테이너는 그때마다 새로운 프로토타입 빈 객체를 반환한다.
싱글톤 빈은 생성 시점에만 의존관계를 주입받는다. 이때 의존관계에 있는 객체 중 프로토타입 스코프를 가진 빈이 있다면, 생성 시점에 하나의 빈을 받고 이후에도 계속 같은 빈을 사용하게 된다. 프로토타입 빈임에도 싱글톤 빈처럼 사용되는 것이다.
@Autowired
private ApplicationContext ac;
public int logic() {
PrototypeBean prototypeBean = ac.getBean(PrototypeBean.class);
prototypeBean.addCount();
int count = prototypeBean.getCount();
return count;
}
의존관계를 외부에서 주입(DI) 받는게 아니라 이렇게 직접 필요한 의존관계를 찾는 것을 Dependency Lookup(DL) 의존관계 조회(탐색) 이라 한다. ⇒ 스프링 컨테이너에 종속적인 코드가 된다.
@Autowired
private ObjectProvider<PrototypeBean> prototypeBeanProvider;
public int logic() {
PrototypeBean prototypeBean = prototypeBeanProvider.getObject();
prototypeBean.addCount();
int count = prototypeBean.getCount();
return count;
}
prototypeBeanProvider.getObject()을 통해 항상 새로운 프로토타입 빈이 생성된다.
ObjectProvider 의 getObject() 를 호출하면 내부에서는 스프링 컨테이너를 통해 해당 빈을 찾아서 반환한다(DL).
⇒ 프로토타입 빈이므로 요청할 때마다 새로운 객체를 만들어서 반환
ObjectFactory, ObjectProvider 특징
@Autowired
private Provider<PrototypeBean> provider;
public int logic() {
PrototypeBean prototypeBean = provider.get();
prototypeBean.addCount();
int count = prototypeBean.getCount();
return count;
}
1. 웹 라이브러리 추가(build.gradle)
implementation 'org.springframework.boot:spring-boot-starter-web'
2. 클래스 작성
@Component
@Scope(value = "request") // request 스코프 지정
public class MyLogger {
// 코드 작성
}
3. 컨트롤러 작성
@RequestMapping("log-demo") // 요청 url
@ResponseBody
public String logDemo(HttpServletRequest request) { // 초기화 당시 request가 없음
String requestURL = request.getRequestURL().toString();
myLogger.setRequestURL(requestURL);
return "OK";
}
이런 식으로 작성하면, 초기화 작업 당시 request가 비어있어 오류가 난다.
request는 하나의 HTTP 요청에 매핑되기 때문에 요청이 들어오기 전까지는 null 값이다.
proxyMode
@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyLogger {
// 코드
}
proxyMode 애노테이션을 설정해주면, 아래와 같은 일들이 일어난다.
1. 스프링 빈의 이벤트 라이프사이클을 나열하시오.
2. 스프링이 제공하는 빈 생명주기 콜백 3가지를 나열하시오.
3. 종료메서드(destroyMethod)에는 기본적으로 ( ) 기능이 존재한다.
4. 스프링 컨테이너가 빈 생성과 의존관계 주입까지만 수행하고 더 이상 관리하지 않는 스코프는?
5. 의존관계 주입 대신 의존관계 조회를 통해 주입을 지연시키는 방법에는 어떤 것이 있는가?
Spring 1
EDITOR: PORO
[스프링 1] 3장.스프링 DI (0) | 2022.10.27 |
---|---|
[스프링 1] 2장.스프링 시작하기 (0) | 2022.10.27 |
[스프링1] 컴포넌트 스캔, 의존관계 자동 주입 (0) | 2022.10.13 |
[스프링 1] AppConfig, 스프링 컨테이너, 싱글톤 (0) | 2022.10.06 |
[스프링1] 객체 지향 설계와 스프링, DI (1) | 2022.09.29 |