스프링에서 의존성 주입이란 객체 간의 의존 관계를 외부에서 주입해주는 것을 의미합니다. 객체가 직접 필요한 의존 객체를 생성하거나 찾는 것이 아니라, 외부에서 제공된다는 개념입니다.
조금만 풀어서 다시 설명하면, 클래스 내부에서 다른 클래스의 인스턴스를 직접 생성하거나, 정적 메소드를 사용하여 객체를 얻는다면 이것은 강한 결합을 초래하여 하나의 클래스를 수정할 때, 결합된 다른 클래스들도 함께 수정해야만 하고 Mock 객체를 사용한 테스트가 어려워지는 등의 단점이 발생하는데, 이런 단점을 해결하기 위해 객체 간 의존 관계를 외부에서 주입하는 DI를 사용합니다. (결합도를 낮추어 코드의 유연성을 높임)
*의존성 : 객체 지향 프로그래밍에서 하나의 객체가 다른 객체를 필요로 하거나 사용하는 관계
의존성 주입 방법에는 생성자 주입, 필드 주입, 세터 주입 등이 있습니다. 이 중에서 생성자 주입이 가장 권장되는데 의존성이 필수적이거나 변경될 수 없을 때 사용합니다. 개발을 하다보면 의존 관계가 변경되어야 하는 상황은 거의 없기 때문에 필드 주입과 세터 주입으로 인한 코드의 수정 가능성을 열어두지 않는 것이 좋습니다.
의존성 주입이 필요한 이유
public class Car {
private Engine engine;
public Car() {
this.engine = new Engine();
}
}
1. Engine 클래스의 생성자에 변경이 발생하면, 예를 들어 ElectricEngine이나 HybridEngine을 사용하려면 Car 클래스를 수정해야함
2. 객체가 아닌 클래스 간의 관계가 맺어짐 -> 객체 지향적 설계를 위하여 인터페이스를 사용하여 구체 클래스에 대한 의존을 줄이고 (이는 다형성을 통해 가능해진다.) 해당 인터페이스 타입을 통해 객체를 사용할 수 있도록 해야한다.
의존성 주입을 사용 했을 때
public interface Vehicle {
}
public class Engine implements Vehicle {
}
@Autowired
public class Car {
private Vehicle vehicle;
public Car(Vehicle vehicle) {
this.vehicle = vehicle;
}
}
Car 클래스는 다양한 Vehicle 구현체와 함께 사용할 수 있습니다. 예를 들어, ElectricEngine이나 HybridEngine 등의 새로운 구현체를 추가할 때 Car 클래스를 수정할 필요가 없습니다.
테스트 진행시에도 Vehicle 인터페이스의 목(mock) 객체를 쉽게 주입받아 사용할 수 있습니다. 이는 단위 테스트를 더 쉽게 작성할 수 있게 합니다.
의존성 주입 방법
생성자 주입
@Service
public class MemberService {
private final MemberRepository memberRepository;
@Autowired // 생략 가능
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
생성자 주입 방식에서는 객체가 생성될 때 생성자가 한 번 호출되며, 이 시점에 필요한 의존성들이 주입됩니다. 이는 생성자가 객체 초기화 과정에서 반드시 호출되기 때문입니다.
@Autowired 어노테이션은 스프링 프레임워크에서 의존성 주입(Dependency Injection)을 자동으로 수행할 때 사용하는 어노테이션입니다. 이 어노테이션을 사용하면 스프링 컨테이너가 필요한 빈(Bean)을 찾아서 자동으로 주입해줍니다. @Autowired는 생성자, 세터 메서드, 필드에 사용할 수 있습니다. (스프링 4.3부터는 단일 생성자를 가진 클래스에는 자동으로 @Autowired가 적용되어 생략이 가능)
* 스프링 빈에 대해서는 https://bum0w0.tistory.com/4에 정리해 두었습니다.
세터 주입
@Service
public class MemberService {
private MemberRepository memberRepository;
@Autowired
public void setMemberRepository(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
세터 주입 방식에서는 생성자를 통해 의존성을 주입받는 대신, 세터 메서드를 통해 의존성을 주입받게 됩니다. setMemberRepository 메서드에 @Autowired 어노테이션을 붙여서 스프링이 이 메서드를 통해 MemberRepository 빈을 주입하도록 합니다. 하지만 객체의 불변성을 보장하지 못하는 단점이 있습니다.
필드 주입
@Service
public class MemberService {
@Autowired
private MemberRepository memberRepository;
}
필드에 직접 @Autowired 어노테이션을 붙여서 의존성을 주입합니다. memberRepository 필드에 @Autowired 어노테이션을 붙여서 스프링이 이 필드에 MemberRepository 빈을 주입하도록 합니다.
'Spring' 카테고리의 다른 글
[Spring] BeanFactory와 ApplicationContext(스프링 컨테이너) (1) | 2024.07.20 |
---|---|
[Spring] SpringBoot 와 React 연동하고 빌드하기 (1) | 2024.07.07 |
[Spring] 스프링 빈(Bean) 의 개념 (0) | 2024.07.02 |
[Spring] spring-boot-devtools로 소스코드 수정 후 바로 적용하기 (0) | 2024.06.26 |