Spring을 사용하며 IoC와 DI라는 말을 굉장히 많이 들어봤고, 그것을 활용한다는 말을 굉장히 많이 들어왔는데 IoC와 DI가 정확히 무엇이고, 어떤 식으로 활용되는지는 자세히 알지 못한다. 오늘은 그것에 대해서 알아볼 것이다.
IoC는 말 그대로 제어의 역전을 의미하며, 전통적인 프로그래밍에서는 개발자가 프로그램의 흐름과 제어를 직접 다루는 반면, IoC는 프레임워크가 객체의 생성, 관리, 제어 흐름을 담당하도록 변경하는 개념이다. Spring은 이를 지원하기 위해 ApplicationContext라는 컨테이너를 제공한다.
ApplicationContext는 애플리케이션의 컴포넌트를 생성하고 조립하며, 객체의 라이프사이클을 관리한다.
1. 객체의 생성 및 관리:
- ApplicationContext를 사용하여 빈(Bean)을 생성하고, 관리한다.
- 빈은 일반적으로 Spring이 제어하며, 개발자는 객체의 생성과 관리를 직접 처리하지 않는다.
2. 의존성 관리:
- 객체 간의 의존성을 Spring이 주입(DI)한다.
- 객체가 필요로 하는 다른 객체를 직접 생성하거나 찾는 대신, Spring 컨테이너가 의존성을 주입해주다.
3. 제어 흐름의 역전:
- 개발자가 코드의 제어 흐름을 결정하지 않고, 프레임워크가 객체의 라이프사이클 및 실행 흐름을 관리한다.
DI는 객체 간의 의존성을 프레임워크가 주입하는 개념이다. 객체가 직접 의존하는 객체를 생성하거나 참조하는 대신, 이러한 의존성을 외부에서 주입받도록 한다. Spring은 다양한 방법으로 DI를 지원한다.
public class UserService {
private UserRepository userRepository;
public UserService() {
this.userRepository = new UserRepository(); // 직접 생성
}
// ...
}
위의 코드에서는 'UserService'는 직접적으로 'UserRepository'를 생성하고 의존하고 있다. 이로 인해서 'UserService'와 'UserRepository' 간에 강한 결합이 형성되어 있다. 이런 경우 유지 보수성이 떨어지며, 코드 변경 시 여러 클랠스에 영향을 줄 수 있다.
public class UserService {
private UserRepository userRepository;
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
// ...
}
public class OrderService {
private PaymentGateway paymentGateway;
@Autowired
public void setPaymentGateway(PaymentGateway paymentGateway) {
this.paymentGateway = paymentGateway;
}
// ...
}
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
// ...
}
@Component
public class ReportGenerator {
private EmailService emailService;
@Autowired
public void setEmailService(EmailService emailService) {
this.emailService = emailService;
}
public void generateReport() {
// Use the emailService here...
}
}
public class OrderService {
private PaymentGateway paymentGateway;
@Autowired
public OrderService(@Qualifier("creditCardGateway") PaymentGateway paymentGateway) {
this.paymentGateway = paymentGateway;
}
// ...
}
<bean id="userService" class="com.example.UserService">
<constructor-arg ref="userRepository" />
</bean>
<bean id="userRepository" class="com.example.UserRepository" />
@Configuration
public class AppConfig {
@Bean
public UserService userService(UserRepository userRepository) {
return new UserService(userRepository);
}
@Bean
public UserRepository userRepository() {
return new UserRepository();
}
}
Spring의 IoC와 DI는 코드의 모듈화, 테스트 용이성, 유지보수성 등을 향상시키는 중요한 원리로서, Spring의 핵심 기능 중 하나로, 우리가 Spring으로 프로젝트를 구현하기 위해 항상 사용하던 것들이었다.