티스토리 뷰
빈 생명주기 콜백이란
DB Connection pool - 애플리케이션 서버와 DB 서버를 연결하여 미리 connection을 생성해 두는 것
(자세한 것 아님, 간단한 요약)
DB connection pool이나 네트워크 소켓같이 애플리케이션 종료 시점에 연결을 모두 종료하려는
작업을 할 때, 객체의 초기화와 종료작업이 필요함
스프링 빈은 객체 생성 후 의존관계 주입이라는 사이클을 갖는다( 생성자 주입은 예외 )
즉, 의존관계 주입이 끝나야 데이터를 사용할 수 있는 준비가 완료되는 것이다.
의존관계 주입이 완료된 시점을 알 수 있는 방법이 바로 콜백이다.
스프링 컨테이너 생성 -> 스프링 빈 생성 -> 의존관계 주입 -> 초기화 콜백 -> 사용
-> 소멸 전 콜백 -> 스프링 종료( <- 싱글톤인 이벤트 라이프사이클 )
스프링이 지원하는 빈 생명주기 콜백
1. 인터페이스(InitializingBean - 초기화 , DisposableBean - 종료)
-> 이는 스프링 전용 인터페이스, 그렇기에 의존적이고 메서드 이름을 변경할 수 없는 단점이 있다.
2. 빈 등록 초기화, 소멸 메서드
-> 메서드 이름을 변경할 수 있고, 설정 정보를 사용하기에 외부 라이브러리에서도 적용 가능
-> @Bean의 destroyMethod는 기본 값이 infeerred 추론이다.
그래서 값을 지정하지 않아도 close, shutdown(이 둘이 종료 관례) 이름의 메서드를 자동으로 호출해준다.
3. 애노테이션 @PostConstruct, @PreDestroy
-> 패키지가 javax.annotation. 이다. 자바 표준이기에 다른 컨테이너에서도 잘 동작한다.
유일한 단점은 외부 라이브러리에 적용을 하지 못한다는 점 - 이 부분은 2번 @Bean을 사용하자
빈 스코프
스프링 빈이 스프링 컨테이너의 시작과 함께 생성되어 종료때까지 유지된다
-> 이는 스프링 빈이 기본적으로 싱글톤 스코프로 생성되기 때문
빈 스코프는 빈이 존재하는 범위를 뜻한다.
스프링이 지원하는 스코프 종류
1. 싱글톤 - 기본, 스프링 컨테이너의 시작과 종료까지 유지되는 가장 넓은 범위 *
2. 프로토타입 - 빈의 생성과 의존관계 주입까지만 관여하는 짧은 범위 *
3. 웹 관련 스코프
request - 웹 요청이 들어오고 나갈때까지 유지되는 스코프 *
session - 웹 세션이 생성되고 종료때까지 유지되는 스코프
application - 웹의 서블릿 컨텍스와 같은 범위로 유지되는 스코프
프로토타입 스코프
싱글톤 스코프는 빈을 조회하면 항상 같은 인스턴스를 반환한다.
반면, 프로토타입 스코프는 항상 새로운 인스턴스를 반환한다.
클라이언트가 요청을 할 시점에 새로운 빈을 생성하여 의존관계를 주입하고, 클라이언트에 반환한다.
이후 관리하지 않고, 관리를 하더라도 클라이언트의 책임이 있는 설정이다.
프로토타입 스코프와 싱글톤 빈을 함께 사용하면 발생하는 문제점
프로토타입 빈을 사용하려는 경우 - 각각의 인스턴스를 생성하여 확인하는 ( 각 사용자의 방문 수 등.. )
싱글톤 빈은 생성 시점에만 의존관계를 주입받는다.
그렇기에 이때 생성되는 프로토타입 빈은 싱글톤 빈과 함께 주입 받고 계속 유지되는 것
-> 문제가 되는 이유? A이용자의 방문 수와 B이용자의 방문 수가 공유되어 증가되는 문제가 있을 수도
어떻게 사용할 때마다 프로토타입 빈을 생성할 수 있을까?
@Autowired
private ApplicationContext ac;
public int logic() {
PrototypeBean prototypeBean = ac.getBean(PrototypeBean.class);
prototypeBean.addCount();
int count = prototypeBean.getCount();
return count;
}
위 코드를 보면 logic이 실행될 때 프로토타입 빈을 생성하여 이전 로직을 수행한다.
이렇게 한다면 logic 실행 마다 생성되기 때문에 서로 다른 프로토타입 빈을 사용할 수 있다.
이런 방식처럼 의존관계를 외부에서 주입받는 것이 아닌 직접 의존관계를 찾는 것을 DL(Dependency Lookup, 의존관계) 이라 한다.
위 코드는 로직마다 ApplicationContext를 주입받으면 스프링 컨테이너에 종속적이게 된다.
DL 기능만 제공하는 ObjectProvider와 JSR-330 Provider
1. ObjectProvider (ObjectFactory)
@Autowired
private ObjectProvider<PrototypeBean> prototypeBeanProvider;
public int logic() {
PrototypeBean prototypeBean = prototypeBeanProvider.getObject();
prototypeBean.addCount();
int count = prototypeBean.getCount();
return count;
}
이전 코드와 비슷한 맥락이다. 단 ObjectProvider의 getObject메서드는 스프링 컨테니어를 통해 해당 빈을 찾아 제공한다.
2. JSR-330 Provider
@Autowired
private Provider<PrototypeBean> provider;
public int logic() {
PrototypeBean prototypeBean = provider.get();
prototypeBean.addCount();
int count = prototypeBean.getCount();
return count;
}
이는 자바 표준 javax.inject.Provider를 사용한다. - ( 부트 3.0미만 가능, 이상은 jakarta.inject.Provider )
ObjectProvider와 마찬가지로 동작하며, 이는 라이브러리를 추가해야 하지만 자바 표준이기 때문에 다른 컨테이너에도 적용 가능하다.
웹 스코프
웹 스코프는 웹 환경에서만 동작하고, 스프링이 해당 스코프의 종료시점까지 관리한다.
1. request - HTTP 요청 하나가 들어오고 나갈 때 까지 유지되는 스코프, 각 요청마다 별도의 빈 인스턴스 생성 및 관리
2. session: HTTP Session과 동일한 생명주기를 가지는 스코프
3. application: 서블릿 컨텍스트( ServletContext )와 동일한 생명주기를 가지는 스코프
4. websocket: 웹 소켓과 동일한 생명주기를 가지는 스코프
스코프와 프록시
프록시 - "대리"의 의미로, 내부 네트워크에서 인터넷 접속을 할 때에, 빠른 액세스나 안전한 통신등을 확보하기 위한
중계서버를 "프록시 서버"라고 일컫는다. 클라이언트와 Web서버의 중간에 위치하고 있어,
대신 통신을 받아 주는 것이 프록시 서버이다. -> 대신, 가짜로
CGLIB 라이브러리로 가짜 프록시 객체를 만들고, 이 객체가 MyLogger대신(프록시하다) 등록된다.
의존관계 주입 또한 가짜 프록시 객체가 주입된다.
이 객체는 요청이 오면 그때 내부에서 진짜 빈을 요청하는 위임 로직이 존재
-> 미리 만들어두고 요청이 오면 찾기 때문에 ObjectProvider 처럼 사용할 수 있다.
본 포스팅은 인프런 강의 김영한님의
[ 스프링 핵심 원리 - 기본편 ] 을 수강하며 작성한 내용입니다.