Spring Container

빈(Bean)을 생성·관리하고 의존성을 주입하는 Spring의 핵심 IoC 컨테이너입니다. 개발자가 직접 new로 객체를 만들지 않고, 컨테이너에 등록된 빈을 가져다 씁니다.

왜 필요한가?

[ 컨테이너 없을 때 ]
public static void main(String[] args) {
    EmailService email = new EmailService();
    NotificationService notification = new NotificationService();
    UserService userService = new UserService(email, notification);
    Controller controller = new Controller(userService);
    // ...

    개발자가 직접 의존성 그래프를 따라가며 객체 생성·연결
    → 객체 수가 많아지면 관리 불가능
}
[ Spring 컨테이너 ]
@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
        ↑ 컨테이너가 모든 빈을 알아서 생성·연결
    }
}

→ 개발자는 "어떤 빈이 필요한지"만 어노테이션으로 선언
→ 어떻게 만들고 연결할지는 컨테이너가 처리

두 가지 인터페이스: BeanFactory vs ApplicationContext

        BeanFactory (최상위)
        └─ ApplicationContext (확장)
            ├─ AnnotationConfigApplicationContext
            ├─ ClassPathXmlApplicationContext
            └─ WebApplicationContext (Spring Web에서 사용)
항목BeanFactoryApplicationContext
역할빈 생성·조회의 가장 기본 기능BeanFactory + 부가 기능
빈 로딩지연(lazy) — 처음 요청 시 생성즉시(eager) — 시작 시 모두 생성
메시지 국제화XO
이벤트 발행XO (ApplicationEvent)
AOP 통합XO
실무 사용거의 안 씀표준

실무에서 "Spring 컨테이너"라고 하면 거의 항상 ApplicationContext를 말함.

빈 등록 방법 3가지

1. 컴포넌트 스캔 (가장 흔함)

@Component
public class EmailService { }

컨테이너가 시작 시 @Component/@Service/@Repository/@Controller가 붙은 클래스를 탐색해서 빈으로 등록.

2. @Bean 메서드 (외부 라이브러리)

@Configuration
public class AppConfig {
    @Bean
    public ObjectMapper objectMapper() {
        return new ObjectMapper();
    }
}

내가 만들지 않은 클래스(라이브러리)를 빈으로 등록할 때 사용.

3. XML 설정 (legacy)

<bean id="emailService" class="com.example.EmailService"/>

요즘은 거의 안 씀.

컨테이너 동작 흐름

[ 애플리케이션 시작 ]

1. ApplicationContext 생성
   ├─ 설정 정보 로딩 (@Configuration 클래스, application.properties 등)

2. 빈 정의 등록 (Bean Definition)
   ├─ @ComponentScan으로 어노테이션 클래스 탐색
   ├─ @Bean 메서드 등록
   └─ "어떤 빈이 있고 어떤 의존성이 필요한지" 메타데이터 수집

3. 빈 인스턴스 생성
   ├─ 의존성 그래프 분석 (위상 정렬)
   ├─ 의존성이 없는 빈부터 순서대로 인스턴스화
   └─ 싱글톤이 기본 (한 번만 생성)

4. 의존성 주입
   ├─ 생성자 주입: 인스턴스화 시점에 동시 처리
   ├─ 필드/세터 주입: 인스턴스 생성 후 처리
   └─ @Autowired로 자동 매칭

5. 빈 후처리 (BeanPostProcessor)
   ├─ AOP 프록시 생성
   ├─ @PostConstruct 호출
   └─ 커스텀 초기화 로직

6. 사용 가능 상태
   └─ 빈 조회·실행

빈 조회 방법

대부분 자동 주입(@Autowired)을 쓰지만, 컨테이너에서 직접 꺼낼 수도 있음:

@SpringBootApplication
public class App implements CommandLineRunner {

    private final ApplicationContext context;

    public App(ApplicationContext context) {
        this.context = context;
    }

    @Override
    public void run(String... args) {
        // 1. 타입으로 조회
        EmailService email = context.getBean(EmailService.class);

        // 2. 이름으로 조회
        EmailService email = (EmailService) context.getBean("emailService");

        // 3. 이름 + 타입
        EmailService email = context.getBean("emailService", EmailService.class);

        // 4. 같은 타입 빈 모두 조회
        Map<String, MailSender> senders = context.getBeansOfType(MailSender.class);
    }
}

직접 조회는 테스트나 디버깅 외에는 잘 안 씀. DI를 쓰는 게 IoC 정신에 맞음.

빈 등록 방식의 우선순위

같은 빈 이름·타입이 여러 곳에서 등록되면:

@Bean 메서드 > 컴포넌트 스캔
   ↑
  설정 클래스의 @Bean이 우선
@Component
public class EmailService { }   // 자동 등록

@Configuration
public class AppConfig {
    @Bean
    public EmailService emailService() {  // 같은 이름의 빈 → 이게 우선
        return new MockEmailService();
    }
}

컨테이너 종류

클래스용도
AnnotationConfigApplicationContext자바 어노테이션 기반 (가장 흔함)
ClassPathXmlApplicationContextXML 기반 (legacy)
AnnotationConfigWebApplicationContext웹 + 어노테이션
WebApplicationContextSpring MVC에서 자동 사용

Spring Boot에서는 SpringApplication.run()이 알아서 적절한 구현체 선택 — 직접 만들 일 거의 없음.

빈 스코프 (간단 소개)

기본은 싱글톤 — 컨테이너당 한 개만 생성

@Component
public class UserService { }   // 컨테이너 전체에서 공유

@Component
@Scope("prototype")
public class TempBuffer { }    // 요청할 때마다 새로 생성

기타: request, session, application, websocket (웹 전용)

자세한 건 별도 노트에서 다룰 예정.

빈 생명주기 (간단 소개)

1. 객체 생성 (constructor)
2. 의존성 주입 (@Autowired)
3. 초기화 콜백 (@PostConstruct)
4. 사용
5. 소멸 콜백 (@PreDestroy)

자세한 건 별도 노트에서 다룰 예정.

핵심 정리

Spring 컨테이너는 빈의 생성·의존성 주입·생명주기를 관리하는 IoC 컨테이너로, 실무에서는 거의 항상 ApplicationContext 인터페이스를 사용합니다. 빈 등록은 @Component 기반 컴포넌트 스캔과 @Bean 메서드 두 가지가 주를 이루며, 컨테이너는 시작 시 빈 정의를 수집한 뒤 의존성 그래프를 따라 순서대로 인스턴스화합니다. 개발자는 빈 조회를 직접 하기보다 DI를 통해 받는 것이 IoC 원칙에 맞으며, Spring Boot는 SpringApplication.run() 한 줄로 적절한 컨테이너를 자동 구성해줍니다.

CSLOG에서 보기