필수 의존성
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
IOC(Inversion of Control)의 본질
객체 생성의 주도권을 개발자에서 프레임워크로 이전하는 설계 원칙이다. Spring 컨테이너가 객체를 생성·관리하며, 필요 시점에 컨테이너에서 주입받아 사용한다.
Bean 생성 전략 3가지
| 방식 | 설명 | 적용 상황 |
|---|---|---|
| 기본 생성자 | 파라미터 없는 생성자로 인스턴스화 | 일반적인 POJO |
| 정적 팩토리 메서드 | 클래스의 static 메서드로 객체 생성 | 외부 라이브러리 통합 |
| 인스턴스 팩토리 메서드 | 별도 팩토리 객체의 메서드로 생성 | 복잡한 초기화 로직 |
Bean 스코프와 생명주기
scope 속성으로 Bean의 존재 범위를 제어한다.
<bean id="orderRepository" class="com.example.infra.OrderRepositoryImpl" scope="prototype"/>
| 특성 | singleton (기본값) | prototype |
|---|---|---|
| 인스턴스 수 | 컨테이너당 1개 | 요청 시마다 새로 생성 |
| 생성 시점 | 컨텍스트 로딩 시 | getBean() 호출 시 |
| 소멸 시점 | 컨테이너 종료 시 | 가비지 컬렉션 대상 |
생명주기 콜백은 init-method와 destroy-method로 지정한다.
<bean id="cacheManager" class="com.example.cache.RedisManager"
init-method="warmUp"
destroy-method="flushAll"/>
DI(Dependency Injection) 구현 방식
IOC의 구체적 구현체로, 실행 시점에 의존 관계를 외부에서 설정한다.
생성자 주입
public class PaymentService {
private final TransactionLogger txLogger;
public PaymentService(TransactionLogger txLogger) {
this.txLogger = txLogger;
}
}
Setter 주입
public class NotificationService {
private MessageSender sender;
public void setMessageSender(MessageSender sender) {
this.sender = sender;
}
}
다양한 타입 주입
<!-- 기본형 데이터 -->
<property name="maxRetry" value="3"/>
<!-- 컬렉션 -->
<property name="excludedHosts">
<list>
<value>localhost</value>
<value>127.0.0.1</value>
</list>
</property>
설정 분리와 모듈화
대규모 프로젝트에서는 설정을 기능별로 분리하여 관리한다.
<!-- applicationContext.xml -->
<import resource="classpath:datasource-config.xml"/>
<import resource="classpath:security-context.xml"/>
<import resource="classpath:messaging-beans.xml"/>
컨테이너 API 활용
| 구현체 | 용도 |
|---|---|
| ClassPathXmlApplicationContext | 클래스패스 기반 XML 로딩 |
| FileSystemXmlApplicationContext | 파일 시스템 경로 로딩 |
| AnnotationConfigApplicationContext | 자바 어노테이션 기반 설정 |
// 타입 기반 조회 (단일 Bean)
PaymentProcessor processor = context.getBean(PaymentProcessor.class);
// 이름 기반 조회
PaymentProcessor processor = (PaymentProcessor) context.getBean("paypalProcessor");
외부 리소스 연동: DataSource 예시
<!-- 네임스페이스 선언 -->
<beans xmlns:context="http://www.springframework.org/schema/context"
...>
<!-- 프로티 파일 외부화 -->
<context:property-placeholder location="classpath:db.properties"/>
<bean id="dataPool" class="com.zaxxer.hikari.HikariDataSource">
<property name="jdbcUrl" value="${database.url}"/>
<property name="username" value="${database.user}"/>
<property name="password" value="${database.password}"/>
</bean>
어노테이션 기반 설정
레거시 어노테이션 (Bean 정의 대체)
@Component
public class InventoryRepository {
@Autowired
public InventoryRepository(@Qualifier("master") DataSource ds) { }
}
자바 기반 설정 (XML 완전 대체)
@Configuration
public class AppConfig {
@Bean
@Profile("production")
public CacheManager redisCacheManager() {
return new RedisCacheManager();
}
}