Spring IoC 컨테이너 완벽 가이드: 빈 생명주기부터 의존성 주입까지

1. Spring IoC의 동작 원리

1.1 IoC 개요

Spring은 XML 설정 파일이나 어노테이션을 활용해 빈(Bean) 간의 의존 관계를 정의한다. 자바의 리플렉션(Reflection) 메커니즘을 통해 빈을 생성하고 관계를 설정하며, IoC 컨테이너는 빈 인스턴스 캐싱, 프록시 생성, 이벤트 발행, 리소스 관리 등 고급 서비스를 제공한다.

1.2 빈 조립 과정

Spring이 구동되면 XML 또는 어노테이션에서 제공된 빈 설정 정보를 읽어 빈 설정 레지스트리를 생성한다. 이 레지스트리를 기반으로 빈을 인스턴스화하고 의존 관계를 조립하여 애플리케이션 실행 환경을 구성한다. 빈 캐시 풀은 내부적으로 HashMap으로 구현된다.

1.3 빈 스코프(Scope)의 종류

Spring은 다섯 가지 빈 스코프를 제공한다:

1) Singleton (싱글톤)

IoC 컨테이너에 단 하나의 빈 인스턴스만 존재한다. 여러 참조가 동일한 객체를 가리키며, 멀티스레드 환경에서 안전하다. 기본 스코프이며, 다음과 같이 설정한다:

<bean id="userDao" class="com.example.UserDaoImpl" scope="singleton"/>

2) Prototype (프로토타입)

요청 시마다 새로운 빈 인스턴스를 생성한다. 각 인스턴스는 고유한 상태를 가지므로, 유상태(Stateful) 빈에 주로 사용된다. 무상태(Stateless) 빈에는 싱글톤을 권장한다:

<bean id="userService" class="com.example.UserService" scope="prototype"/>

3) Request (요청 스코프)

단일 HTTP 요청 내에서 동일한 빈 인스턴스를 반환한다. 요청이 종료되면 빈도 소멸된다:

<bean id="loginAction" class="com.example.LoginAction" scope="request"/>

4) Session (세션 스코프)

하나의 HTTP 세션 내에서 동일한 인스턴스를 재사용한다. 세션이 다르면 새로운 빈이 생성되며, 각 세션 내에서만 유효하다:

<bean id="userSession" class="com.example.UserSession" scope="session"/>

5) Global Session (글로벌 세션)

Portlet 환경에서 글로벌 HTTP 세션 범위로 동작한다. 일반적인 서블릿 기반 환경에서는 session과 동일하게 처리된다.

1.4 빈 생명주기 상세

빈의 생명주기는 다음과 같은 순서로 진행된다:

  1. 빈 인스턴스화
  2. 설정 정보 기반 의존성 주입
  3. BeanNameAware 구현 시 setBeanName() 호출 (빈 ID 전달)
  4. ApplicationContextAware 구현 시 setApplicationContext() 호출
  5. BeanPostProcessorpostProcessBeforeInitialization() 실행 (초기화 전 처리)
  6. init-method 속성에 지정된 메서드 호출
  7. BeanPostProcessorpostProcessAfterInitialization() 실행 (초기화 완료)
  8. 애플리케이션에서 빈 사용
  9. 컨테이너 종료 시 DisposableBeandestroy() 호출
  10. destroy-method 속성에 지정된 메서드 호출

1.5 네 가지 의존성 주입 방식

1) 생성자 주입 (Constructor Injection)

클래스 생성자를 통해 의존성을 주입한다. <constructor-arg> 태그를 사용한다:

public class PersonDaoImpl {
    private String message;

    public PersonDaoImpl(String message) {
        this.message = message;
    }
}

// XML 설정
<bean id="personDao" class="com.example.PersonDaoImpl">
    <constructor-arg value="환영 메시지" />
</bean>

2) Setter 주입 (Setter Injection)

프로퍼티의 setter 메서드를 통해 주입한다. <property> 태그를 사용한다:

public class PersonDaoImpl {
    private int id;

    public int getId() { return id; }
    public void setId(int id) { this.id = id; }
}

// XML 설정
<bean id="personDao" class="com.example.PersonDaoImpl">
    <property name="id" value="123" />
</bean>

3) 정적 팩토리 주입 (Static Factory Injection)

팩토리 클래스의 정적 메서드를 통해 빈을 생성한다. factory-method 속성을 지정한다:

public class DaoFactory {
    public static FactoryDao createStaticFactoryDao() {
        return new StaticFactoryDaoImpl();
    }
}

public class SpringAction {
    private FactoryDao factoryDao;
    
    public void setFactoryDao(FactoryDao factoryDao) {
        this.factoryDao = factoryDao;
    }
}

// XML 설정
<bean id="staticFactoryDao" class="com.example.DaoFactory"
      factory-method="createStaticFactoryDao" />
<bean id="springAction" class="com.example.SpringAction">
    <property name="factoryDao" ref="staticFactoryDao" />
</bean>

1.6 다섯 가지 자동 조립 방식

Spring은 자동 의존성 주입을 위해 다섯 가지 모드를 지원한다:

  • no: 자동 조립 비활성화 (기본값)
  • byName: 빈의 속성 이름과 동일한 이름의 빈을 자동으로 매칭
  • byType: 빈의 속성 타입과 동일한 타입의 빈을 자동으로 매칭
  • constructor: 생성자 파라미터 타입에 맞춰 자동 조립, 일치하는 생성자가 없으면 예외 발생
  • autodetect: 먼저 constructor 방식 시도, 실패 시 byType으로 대체

예를 들어 byName 방식은 다음과 같이 적용한다:

<bean id="userService" class="com.example.UserService" autowire="byName" />

태그: Spring IOC 의존성주입 빈생명주기 스프링스코프

6월 8일 18:23에 게시됨