스프링 빈은 스프링 컨테이너가 생성과 관계 설정, 사용 등을 제어해주는 IoC가 적용된 객체를 가리키는 말이다.
빈 생성
스프링 컨테이너는 xml, java 등 다양한 형식의 설정 정보를 BeanDefinition 으로 추상화해서 사용.
BeanDefinition 를 통해 빈 메타 정보를 생성하고 이걸 기반으로 스프링 빈 생성.
빈 등록
- 자동 빈 등록 -> @ComponentScan
- 수동 빈 등록 -> @Configuration
@Bean은 메소드 레벨에서 선언하며, 반환되는 객체(인스턴스)를 개발자가 수동으로 빈으로 등록하는 애노테이션이다. 반면 @Component는 클래스 레벨에서 선언함으로써 스프링이 런타임시에 컴포넌트스캔을 하여 자동으로 빈을 찾고(detect) 등록하는 애노테이션이다.
조회 빈이 2개 이상일 경우
- @Autowired
- 타입 매칭을 시도하고, 이때 여러 빈이 있으면 필드 이름, 파라미터 이름으로 빈 이름을 매칭
- @Qualifier
- @Qualifier 끼리 매칭
- @Primary
- @Autowired 시에 여러 빈이 매칭되면 @Primary 가 우선권을 가진다.
빈 스코프
- Singleton
- 스프링 빈은 스프링 컨테이너의 시작과 함께 생성되어서 스프링 컨테이너가 종료될 때까지 1개의 객체로 유지
- Prototype
- 요청이 오면 항상 새로운 인스턴스를 생성하여 반환하고 이후에 관리하지 않음
- 프로토타입을 받은 클라이언트가 객체를 관리해야 함
- 스프링 컨테이너는 프로토타입 스프링 빈의 생성과 의존관계 주입까지만 관여하고 이후의 과정은 관여하지 않는다. (이후는 해당 빈을 호출한 사용자에 의해서 종료된다.) 스프링 컨테이너는 프로토타입 빈을 생성하고 의존관계 주입, 초기화까지만 처리.
@PreDestroy같은 종료 메서드가 호출 되지 않는다.
- 스프링 컨테이너는 프로토타입 스프링 빈의 생성과 의존관계 주입까지만 관여하고 이후의 과정은 관여하지 않는다. (이후는 해당 빈을 호출한 사용자에 의해서 종료된다.) 스프링 컨테이너는 프로토타입 빈을 생성하고 의존관계 주입, 초기화까지만 처리.
- Web
- Request: 각각의 요청이 들어오고 나갈 때까지 유지되는 scope (HTTP Request의 생명주기와 같음)
- Session: 세션이 생성되고 종료될 때까지 유지되는 scope (HTTP Session의 생명주기와 같음)
- Application: 웹의 서블릿 컨텍스트와 같은 범위로 유지되는 scope
왜 스프링 빈은 기본적으로 싱글톤일까?
Spring Framework의 핵심은 스프링 컨테이너. 이 컨테이너는 객체를 갖고 있다가 필요할때 주입한다. 왜 그렇게 동작할까?
서버는 많은 사람들이 사용하고 그 사용자들이 이용할 비즈니스 로직은 대부분 동일하다.
동일한 비즈니스 로직(빈)이 이용하는 사람들마다 하나씩 생성된다면 서버는 부하에 걸리기 쉽고 애초에 동일한 로직이 여러 개 생성될 필요가 없기 때문에 스프링에서는 빈들을 싱글톤으로 관리한다.
프로토타입 스코프 - 싱글톤 빈과 함께 사용시 문제점
싱글톤 스프링 빈 내부에 의존관계로 주입되는 스프링 빈이 프로토타입인 경우
프로토타입 스코프의 스프링 빈이 새로 생성되기는 했지만 싱글톤 빈과 함께 사용되기 때문에 계속 유지된다.
싱글톤 빈과 함께 사용하면서 프로토타입 빈이 자기의 스코프를 지키고 매번 새롭게 생성하기 위해서는 어떻게 해야 할까?
의존관계를 외부에서 주입(DI) 받는 것이 아닌 직접 필요한 의존관계를 찾는 것을 Dependency Lookup(DL) 의존관계 조회(탐색)이라 한다.
ObjectProvider의 getObject()를 호출하면 내부에서 스프링 컨테이너를 통해 해당 빈을 찾아서 반환한다.(DL)
스프링의 의존성이 마음에 들지 않으면 JSR-330 자바 표전을 사용하는 방법이 있다.
프로토타입 빈을 언제 사용해야 하는가?
- 여러 인스턴스를 검색해야 하는 경우
- 인스턴스를 지연 혹은 선택적으로 찾아야 하는 경우
- 순환 종속성을 깨기 위해서
- 스코프에 포함된 인스턴스로부터 더 작은 범위의 인스턴스를 찾아 추상화 하기 위해서 사용한다.
빈 라이프사이클
스프링 IoC 컨테이너 생성 → 스프링 빈 생성 → 의존관계 주입 → 초기화 콜백 메소드 호출 → 사용 → 소멸 전 콜백 메소드 호출 → 스프링 종료
스프링은 크게 3가지 방법으로 빈 생명주기 콜백을 관리
1. 인터페이스( InitializingBean, DisposableBean )
- 인터페이스를 상속받아 초기화 메서드, 소멸전 메서드를 구현할 수 있다.
- 스프링 전용 인터페이스
2. 설정 정보에 초기화 메소드, 종료 메소드 지정
- 스프링 빈이 스프링 코드에 의존하지 않는다.
- 코드가 아닌 설정 정보를 사용하기 때문에 외부 라이브러리에도 초기화, 종료 메서드 적용 가능
3. @PostConstruct, @PreDestroy 어노테이션 지원
- 최신 스프링에서 가장 권장하는 방법
- 사용하기 편리하다.
- 스프링 종속 기술이 아닌 JSR-250 자바 표준
- 외부 라이브러리에는 적용하지 못한다.