컨테이너가 prototype 인스턴스의 전체 생명주기와 destruction callback을 singleton처럼 끝까지 관리하지 않기 때문이다.
BeanPostProcessor와 확장 포인트
3줄 요약
BeanPostProcessor는 Bean 초기화 전후에 개입해 Bean 인스턴스를 감싸거나 바꿀 수 있는 확장 포인트다.
AOP Proxy, @Autowired, @PostConstruct 같은 많은 Spring 기능은 컨테이너 확장 포인트 위에서 동작한다.
BeanPostProcessor는 강력하지만 모든 Bean 생성 흐름에 영향을 줄 수 있으므로 좁고 명확한 책임으로 사용해야 한다.
핵심 정리
BeanFactoryPostProcessor는 Bean 인스턴스가 만들어지기 전 BeanDefinition 단계에 개입한다.
BeanPostProcessor는 Bean 인스턴스 생성 후 초기화 전후에 개입한다.
AOP 자동 프록시 생성은 BeanPostProcessor 계열이 Bean을 검사하고 필요하면 Proxy로 대체하는 방식과 연결된다.
@Autowired나 @PostConstruct 같은 애너테이션 처리도 단순 문법이 아니라 컨테이너 후처리기들의 작업 결과다.
확장 포인트를 이해하면 Spring의 “마법”이 언제 BeanDefinition을 바꾸고 언제 Bean 인스턴스를 바꾸는지 구분할 수 있다.
BeanPostProcessor는 컨테이너 단위로 동작하며, 후처리기 자신이나 후처리기가 너무 일찍 끌어온 Bean은 모든 후처리와 자동 프록시 대상에서 제외될 수 있다.
헷갈리는 지점
BeanPostProcessor를 직접 자주 구현해야 하는 기능으로 오해하기 쉽다. 강력한 확장 포인트라는 설명을 듣기 때문이다.
핵심은 직접 구현보다 Spring 내부 기능을 이해하는 관점이 더 자주 필요하다는 점이다.
실무에서는 직접 구현보다 이미 제공되는 확장 포인트와 자동 설정을 정확히 쓰는 경우가 많다.
BeanFactoryPostProcessor와 BeanPostProcessor를 혼동하기 쉽다. 이름이 비슷하기 때문이다.
핵심은 전자는 Bean 정의 단계, 후자는 Bean 인스턴스 단계라는 점이다.
정의를 바꾸는가, 생성된 객체를 후처리하는가로 구분한다.
AOP Proxy가 처음부터 Target 대신 생성된다고 생각하기 쉽다. 결과적으로 주입 객체가 Proxy이기 때문이다.
핵심은 원본 Bean 생성 흐름 이후 후처리 단계에서 Proxy로 감싸질 수 있다는 점이다.
그래서 Bean 생명주기와 AOP는 분리된 주제가 아니라 연결된 주제다.
확인 질문
BeanPostProcessor는 어느 단계에 개입하는가?
Bean 인스턴스 생성 후 초기화 전후 단계에 개입한다.
BeanFactoryPostProcessor와 BeanPostProcessor의 차이는 무엇인가?
BeanFactoryPostProcessor는 BeanDefinition 단계에, BeanPostProcessor는 Bean 인스턴스 단계에 개입한다.
AOP와 BeanPostProcessor는 어떻게 연결되는가?
자동 프록시 생성기가 Bean 후처리 단계에서 대상 Bean을 Proxy로 감싸 노출할 수 있다.
Scope와 Lazy 초기화
3줄 요약
Scope는 Bean 인스턴스가 언제 생성되고 얼마나 공유되는지 결정한다.
기본 Scope는 singleton이며, 하나의 Spring Container 안에서 하나의 Bean 인스턴스를 공유한다.
lazy 초기화는 Bean 생성을 시작 시점이 아니라 실제 요청 시점으로 미루지만, 오류 발견도 늦출 수 있다.
핵심 정리
singleton은 Spring Container당 하나의 Bean 인스턴스를 의미한다.
prototype은 요청할 때마다 새 인스턴스를 만들지만, 생성 이후의 전체 생명주기를 컨테이너가 계속 관리하지 않고 destruction callback도 호출하지 않는다.
web scope에는 request, session, application, websocket 등이 있으며 웹 애플리케이션 컨텍스트에서만 자연스럽게 동작한다.
lazy initialization은 시작 시간을 줄일 수 있지만 Bean 생성 오류를 런타임 요청 시점으로 미룰 수 있다.
singleton Bean이 prototype Bean을 주입받으면 주입 시점의 prototype 인스턴스 하나만 들고 있을 수 있으므로, 매번 새 prototype이 필요하면 ObjectProvider, lookup method, scoped proxy 같은 조회 지연 전략이 필요하다.
헷갈리는 지점
singleton을 JVM 전체에서 하나라고 생각하기 쉽다. 싱글톤이라는 이름 때문이다.
핵심은 Spring singleton은 컨테이너당 하나라는 점이다.
ApplicationContext가 다르면 같은 Bean 정의라도 다른 인스턴스가 생길 수 있다.
prototype을 쓰면 모든 생명주기 관리가 자동으로 된다고 생각하기 쉽다. Spring이 생성해 주기 때문이다.
핵심은 prototype은 생성 이후 관리 범위가 제한적이라는 점이다.
리소스를 잡는 prototype Bean은 정리 책임을 별도로 설계해야 한다.
lazy 초기화를 성능 최적화로만 보기 쉽다. 시작 시간이 줄어드는 효과가 있기 때문이다.
핵심은 오류 발견 시점도 늦어진다는 점이다.
핵심 Bean은 eager 생성으로 빠르게 검증하는 편이 운영 안정성에 유리할 수 있다.
확인 질문
Spring singleton은 무엇을 의미하는가?
하나의 Spring Container 안에서 하나의 Bean 인스턴스를 공유한다는 뜻이다.
prototype Bean의 주의점은 무엇인가?
요청마다 새 인스턴스를 만들지만 생성 이후 소멸 관리는 컨테이너가 끝까지 책임지지 않는다.