IoC(제어의 역전) 컨테이너는 객체의 생성 및 관리를 개발자가 아닌 프레임워크(컨테이너)가 대신하도록 하는 개념입니다. 이는 객체의 생성, 초기화, 의존성 설정, 생명 주기 관리를 IoC 컨테이너가 수행하게 함으로써, 개발자는 비즈니스 로직 구현에 집중할 수 있도록 합니다.
스프링 프레임워크에서 IoC 컨테이너는 핵심 컴포넌트이며, 애플리케이션의 빈(bean)을 관리합니다.
빈(Bean) 등록:
빈(Bean) 생성:
의존성 주입:
빈 관리 및 제공:
BeanFactory:
ApplicationContext:
의존성 주입 (Dependency Injection):
@Component
public class MyService {
private final MyRepository repository;
// Constructor Injection
public MyService(MyRepository repository) {
this.repository = repository;
}
}
객체 생명 주기 관리:
@Component
public class MyBean {
@PostConstruct
public void init() {
System.out.println("Initializing bean");
}
@PreDestroy
public void destroy() {
System.out.println("Destroying bean");
}
}
AOP (Aspect-Oriented Programming):
빈 스코프 관리:
인터페이스 주입 (Interface Injection)
public interface Service {
void perform();
}
public interface ServiceConsumer {
void setService(Service service);
}
public class MyService implements Service {
@Override
public void perform() {
System.out.println("Performing service");
}
}
public class MyConsumer implements ServiceConsumer {
private Service service;
@Override
public void setService(Service service) {
this.service = service;
}
}
Setter 주입 (Setter Injection)
@Component
public class MyService {
public void perform() {
System.out.println("Performing service");
}
}
@Component
public class MyConsumer {
private MyService service;
@Autowired
public void setService(MyService service) {
this.service = service;
}
public void execute() {
service.perform();
}
}
생성자 주입 (Constructor Injection)
@Component
public class MyService {
public void perform() {
System.out.println("Performing service");
}
}
@Component
public class MyConsumer {
private final MyService service;
@Autowired
public MyConsumer(MyService service) {
this.service = service;
}
public void execute() {
service.perform();
}
}
컨텍스트 룩업 (Context Lookup)
public class MyConsumer {
public void execute() {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
MyService service = context.getBean(MyService.class);
service.perform();
}
}
| IoC 방식 | 특징 | 장점 | 단점 |
|---|---|---|---|
| 인터페이스 주입 | 인터페이스를 통해 의존성 주입 | 의존성 명시적 선언 | 구현이 번거로움, 사용 적음 |
| Setter 주입 | Setter 메서드를 통해 의존성 주입 | 선택적 의존성 처리 가능 | 객체 생성 후 추가 설정 필요 |
| 생성자 주입 | 생성자를 통해 의존성 주입 | 불변 객체 생성 가능, 의존성 명시적 선언 | 의존성이 많을 경우 생성자 복잡 |
| 컨텍스트 룩업 | 컨테이너에서 의존성 직접 조회 | 즉시 객체 사용 가능 | IoC 원칙에 덜 부합 |
Spring에서는 생성자 주입을 기본적으로 권장하며, 필수 의존성을 명확히 설정하고 불변성을 유지하기에 적합합니다. Setter 주입은 선택적인 의존성을 설정하거나 필요에 따라 활용할 수 있습니다.
컨텍스트 룩업은 의존성을 코드에 노출시키므로 Spring IoC 컨테이너의 장점을 해치며, 인터페이스 주입은 구현이 번거롭고 유지보수에 비효율적이기 때문에 잘 사용되지 않습니다.
코드 재사용성 증가:
유연한 구성:
테스트 용이성:
객체 관리 간소화:
@Configuration
public class AppConfig {
@Bean
public MyRepository myRepository() {
return new MyRepository();
}
@Bean
public MyService myService(MyRepository repository) {
return new MyService(repository);
}
}
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
MyService service = context.getBean(MyService.class);
service.performTask();
}
}
IoC 컨테이너는 객체 관리의 제어권을 개발자가 아닌 프레임워크로 넘기는 방식으로, 애플리케이션을 모듈화하고 관리하기 쉽게 만들어줍니다. Spring IoC 컨테이너는 Java 기반 애플리케이션 개발의 핵심으로, 의존성 주입과 객체 생명 주기 관리를 자동으로 처리하며, 유연성과 테스트 가능성을 크게 향상시킵니다.
추가 학습 자료