IoC(Inversion of Control)와 DI(Dependency Injection)
IoC는 '제어의 역전'이라는 뜻으로, 전통적인 프로그래밍 방식에서 객체의 생성과 관리, 그리고 그 객체들 간의 의존성을 직접적으로 제어하는 방식을 역전시키는 개념
즉, 객체의 생성 및 생명 주기를 개발자가 아닌 프레임워크가 관리한다.
왜 IoC가 필요한가?
유연성 증가: 객체 간의 결합도를 낮추어 코드의 재사용성과 유연성을 높인다.
테스트 용이성: 의존성 주입을 통해 객체를 쉽게 모킹(mocking)할 수 있어 단위 테스트가 용이해진다.
유지보수성 향상: 객체 생성과 의존성 관리가 중앙화되어 코드를 더 쉽게 유지보수할 수 있다.
DI (Dependency Injection)란?
DI는 '의존성 주입'이라는 뜻으로, 객체가 자신의 의존성을 직접 생성하는 것이 아니라 외부에서 주입받는 방식을 의미한다. 스프링에서는 주로 생성자 주입(Constructor Injection), 세터 주입(Setter Injection), 필드 주입(Field Injection) 세 가지 방법을 사용한다.
생성자 주입
생성자 주입은 객체의 생성자에서 의존성을 주입받는 방식이다. 가장 권장되는 방법으로, 불변 객체(immutable object)를 만들 수 있어 안정성이 높다.
java
@Component
public class OrderService {
private final OrderRepository orderRepository;
@Autowired
public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
}
세터 주입
세터 주입은 객체의 세터 메서드를 통해 의존성을 주입받는 방식이다. 선택적인 의존성을 주입할 때 유용하지만, 필수 의존성의 경우 런타임 시점에서 누락될 위험이 있다.
java
@Component
public class OrderService {
private OrderRepository orderRepository;
@Autowired
public void setOrderRepository(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
}
필드 주입
필드 주입은 객체의 필드에 직접 의존성을 주입하는 방식이다. 가장 간단한 방법이지만, 테스트하기 어렵고, 객체의 불변성을 보장할 수 없기 때문에 권장되지 않는다.
java
@Component
public class OrderService {
@Autowired
private OrderRepository orderRepository;
}
스프링에서의 IoC 컨테이너
스프링은 IoC 컨테이너를 제공하여 객체의 생성, 구성, 생명 주기 관리를 담당한다. 대표적인 IoC 컨테이너로는 ApplicationContext가 있으며, XML 설정 파일이나 자바 어노테이션을 통해 빈(Bean)을 정의하고 의존성을 주입할 수 있다.
xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="orderRepository" class="com.example.OrderRepository"/>
<bean id="orderService" class="com.example.OrderService">
<constructor-arg ref="orderRepository"/>
</bean>
</beans>
java
@Configuration
public class AppConfig {
@Bean
public OrderRepository orderRepository() {
return new OrderRepository();
}
@Bean
public OrderService orderService() {
return new OrderService(orderRepository());
}
}