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 빈 생명주기 상세
빈의 생명주기는 다음과 같은 순서로 진행된다:
- 빈 인스턴스화
- 설정 정보 기반 의존성 주입
BeanNameAware구현 시setBeanName()호출 (빈 ID 전달)ApplicationContextAware구현 시setApplicationContext()호출BeanPostProcessor의postProcessBeforeInitialization()실행 (초기화 전 처리)init-method속성에 지정된 메서드 호출BeanPostProcessor의postProcessAfterInitialization()실행 (초기화 완료)- 애플리케이션에서 빈 사용
- 컨테이너 종료 시
DisposableBean의destroy()호출 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" />