IoC와 DI: 개념과 Spring Boot에서 의존성 주입 방법
1. IoC(Inversion of Control)란?
IoC(Inversion of Control, 제어의 역전)는 객체의 생성 및 흐름의 제어 권한을 개발자가 직접 관리하는 것이 아니라 프레임워크(Spring Container)가 관리하도록 하는 개념입니다. 이를 통해 결합도를 낮추고 유연한 애플리케이션을 설계할 수 있습니다.
2. DI(Dependency Injection)란?
DI(Dependency Injection, 의존성 주입)는 IoC를 구현하는 방식 중 하나로, 객체 간의 의존성을 직접 생성하는 것이 아니라 외부에서 주입하는 방식입니다. 이를 통해 코드의 유지보수성과 테스트 용이성이 향상됩니다.
Spring Boot에서는 다양한 방식으로 의존성을 주입할 수 있습니다. 주요 방식은 다음과 같습니다:
- 생성자 주입(Constructor Injection)
- 세터 주입(Setter Injection)
- 필드 주입(Field Injection)
- 인터페이스 기반 주입(Interface-based Injection)
3. Spring Boot에서 의존성 주입하는 4가지 방법
3.1 생성자 주입 (Constructor Injection)
가장 권장되는 방식으로, final 키워드를 활용할 수 있어 불변성을 유지할 수 있으며, 단위 테스트가 용이합니다.
import org.springframework.stereotype.Service;
@Service
public class UserService {
private final UserRepository userRepository;
// 생성자를 통한 의존성 주입
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public void createUser(String name) {
userRepository.save(new User(name));
}
}
import org.springframework.stereotype.Repository;
@Repository
public class UserRepository {
public void save(User user) {
System.out.println("User saved: " + user.getName());
}
}
3.2 세터 주입 (Setter Injection)
객체를 생성한 후 setter 메서드를 통해 의존성을 주입하는 방식입니다. 선택적인 의존성을 주입할 때 유용하지만, 객체의 상태가 변경될 가능성이 있어 주의가 필요합니다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
private UserRepository userRepository;
@Autowired
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
public void createUser(String name) {
userRepository.save(new User(name));
}
}
3.3 필드 주입 (Field Injection)
가장 간단한 방법이지만, 필드에 직접 @Autowired
를 사용하면 의존성이 명확하게 보이지 않고, 테스트 시 객체의 변경이 어려울 수 있습니다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public void createUser(String name) {
userRepository.save(new User(name));
}
}
3.4 인터페이스 기반 주입 (Interface-based Injection)
DI 원칙을 더욱 철저하게 준수하기 위해 인터페이스를 활용하는 방식입니다. 다양한 구현체를 손쉽게 교체할 수 있어 확장성이 뛰어납니다.
import org.springframework.stereotype.Service;
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public void createUser(String name) {
userRepository.save(new User(name));
}
}
public interface UserRepository {
void save(User user);
}
import org.springframework.stereotype.Repository;
@Repository
public class UserRepositoryImpl implements UserRepository {
@Override
public void save(User user) {
System.out.println("User saved: " + user.getName());
}
}
4. 의존성 주입 방식 비교
방식 | 장점 | 단점 |
생성자 주입 | 불변성 유지, 테스트 용이 | 순환 참조 발생 가능 |
세터 주입 | 선택적 의존성 주입 가능 | 불변성이 깨질 위험 |
필드 주입 | 코드가 간결 | 테스트 및 유지보수 어려움 |
인터페이스 기반 주입 | 유연성과 확장성 증가 | 초기 설계가 복잡할 수 있음 |
5. 결론
Spring Boot에서는 다양한 방식으로 의존성을 주입할 수 있으며, 상황에 맞게 적절한 방식을 선택해야 합니다. 일반적으로 생성자 주입이 가장 권장되며, 필요에 따라 세터 주입이나 인터페이스 기반 주입을 활용할 수 있습니다. 필드 주입은 유지보수성과 테스트 용이성 측면에서 권장되지 않습니다.
IoC와 DI를 올바르게 활용하면 결합도를 낮추고 확장성이 높은 애플리케이션을 만들 수 있습니다.
'개발 부트캠프 > 백엔드' 카테고리의 다른 글
[Spring] 서버가 클라이언트로부터 데이터를 전달 받는 방법 (0) | 2025.02.10 |
---|---|
[Spring] @Controller와 @RestController의 차이 (0) | 2025.02.10 |
[Java] DBCP (0) | 2025.01.16 |
[Java] Servlet Filter (0) | 2025.01.16 |
[Java] JSON (0) | 2025.01.16 |