스프링 빈은 스프링 IoC(Inversion of Control, 제어의 역전) 컨테이너가 만들고, 의존성을 연결하고, 생명주기(lifecycle)를 관리하는 평범한 자바 객체(POJO, Plain Old Java Object)다. 컨테이너(ApplicationContext)는 이 빈들을 담는 공간이고, 내가 new로 만든 객체는 컨테이너가 모른다.
빈을 등록하는 두 방법
@Component // 내가 만든 클래스: 붙이기만 하면 스캔 대상
public class OrderService { }
@Configuration
public class AppConfig {
@Bean // 외부 라이브러리 객체 등: 메서드 반환값을 빈으로
public ObjectMapper objectMapper() {
return new ObjectMapper().findAndRegisterModules();
}
}@Component | @Bean | |
|---|---|---|
| 붙이는 곳 | 클래스 | @Configuration 클래스의 메서드 |
| 대상 | 내가 작성한 클래스 | 외부 라이브러리 클래스도 가능 |
| 생성 제어 | 컨테이너가 알아서 | 생성 코드를 내가 작성 |
| 같은 타입 여러 개 | 어렵다 | 메서드마다 하나씩 |
- 스테레오타입(stereotype) 애너테이션
@Service,@Repository,@Controller는 모두@Component의 특수화다. 역할을 드러내고,@Repository는 DB 예외를 스프링 예외로 바꿔 주는 등 부가 기능이 붙는다 @ComponentScan이 어느 패키지를 뒤질지 정한다. 스프링 부트는 메인 클래스 패키지 아래를 자동으로 스캔한다(스프링 부트 자동 설정)- 빈 이름은 기본적으로 메서드명·클래스명(첫 글자 소문자)이다
생명주기
- 기본 싱글턴 빈은 앱 시작 때 미리 만들어진다(eager initialization). 설정 오류를 시작 시점에 잡을 수 있다.
@Lazy를 붙이면 처음 쓸 때 만든다 @PostConstruct는 의존성 주입이 끝난 직후,@PreDestroy는 컨테이너 종료 직전에 호출된다. 연결 풀 정리 등에 쓴다(스프링 부트 3부터jakarta.annotation패키지)- 빈을 하나만 둘지 요청마다 만들지는 빈 스코프가 정한다
stateDiagram-v2 state "생성 (앱 시작 때, @Lazy면 처음 쓸 때)" as New state "의존성 주입" as DI state "@PostConstruct" as Post state "사용" as Use state "@PreDestroy" as Pre [*] --> New New --> DI DI --> Post Post --> Use Use --> Pre: 컨테이너 종료 Pre --> [*]
연결
빈끼리의 연결이 의존성 주입이다. 컨테이너는 원본 대신 프록시를 넣어 트랜잭션·AOP를 끼우기도 한다. "스프링 빈은 컨테이너가 관리하는 싱글턴"이라는 점에서 싱글턴 패턴과 비교해 보면, 클래스가 스스로 하나임을 강제하지 않는다는 점이 다르다. 생성 책임을 바깥으로 빼는 발상은 팩토리 메서드 패턴와도 닮았다.
출처: Spring Framework 문서: IoC 컨테이너와 빈 소개 · 스테레오타입 애너테이션 · @Bean 애너테이션