IoC와 DI에 대해서 알아보자.
스프링의 IoC (Inversion of Control)는 객체 생성과 관리를 개발자가 아닌 프레임워크가 대신 수행하는 개념입니다.
IoC 컨테이너는 일반적으로 컨테이너 안에 객체들을 저장하고 관리합니다. 이를 위해 컨테이너는 다음과 같은 구성 요소를 포함합니다.
Bean
IoC 컨테이너에서 생성되고 관리되는 객체를 의미합니다. Bean은 애플리케이션에서 사용되는 주요 객체들을 의미하며, 컨테이너가 생성, 조립, 관리, 제거합니다.
Container
Bean을 관리하는 역할을 합니다. Bean의 생성과 소멸, 의존성 주입 등을 관리하며, 애플리케이션의 생명주기와 무관(즉 실행 중 어느때든)하게 객체를 관리합니다. 대표적으로 ApplicationContext와 BeanFactory가 있습니다.
Dependency Injection(DI)
Bean 간의 의존성을 주입하는 것을 의미합니다. IoC 컨테이너에서는 Bean을 생성할 때, 자동으로 의존성 주입을 해주며, 이를 통해 객체 간의 결합도를 낮추어 유연하고 확장성 있는 코드를 작성할 수 있습니다.
이러한 IoC 컨테이너의 구성 요소는 개발자가 일일이 생성, 관리하는 것보다 코드의 유연성과 확장성을 높여주기 때문에 매우 유용한 기술입니다.
IoC 컨테이너를 사용하면 다음과 같은 장점이 있습니다.
DI는 객체 간의 의존성을 줄이기 위해 객체를 직접 생성하는 것이 아니라, 필요한 객체를 외부에서 전달받는 패턴입니다. 이는 코드의 유지보수성을 높이고 결합도를 낮추어 유연성을 높이는 데 도움을 줍니다.
DI의 세 가지 방식과 각각의 장단점은 다음과 같습니다.
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
// UserService 인터페이스 메서드 구현 생략
}
장점:
단점:
public class UserServiceImpl implements UserService {
private UserRepository userRepository;
public UserServiceImpl() {}
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
// UserService 인터페이스 메서드 구현 생략
}
장점:
단점:
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
// UserService 인터페이스 메서드 구현 생략
}
장점:
단점:
각각의 방식은 장단점이 있으며, 개발자는 상황에 따라 적절한 방식을 선택하여 사용해야 합니다. 일반적으로 생성자 주입 방식을 권장합니다.