
의존성 주입은 객체 간의 관계(의존성)를 외부에서 관리하고 주입하는 방식이다. 즉, 객체를 직접 생성하는 것이 아니라 외부에서 생성 후 주입시켜 주는 방식을 말한다.
DI를 통해 객체 간의 관계를 동적으로 주입하여 유연성을 확보하고 결합도를 낮출 수 있다.
Spring에서 의존성 주입하는 방법은 총 3가지가 있다.
면접 단골 문제이다. 확실하게 알아두자!
@Autowired
private MemberRepository memberRepository;
@Autowired 어노테이션을 사용하여 필드에 의존성을 주입한다. Spring이 객체를 생성할 때 자동으로 의존성이 주입된다.
장점: 코드가 간결하다.
단점: 주입된 객체를 외부에서 변경이 불가능하기 때문에, 테스트를 진행할 때와 같이 의존성을 바꿔야 할 때, 변경할 수 없다.
private MemberRepository memberRepository;
@Autowired
public void setMemberRepository(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
의존성 객체를 setter 메서드를 통해 주입한다. @Autowired 어노테이션을 통해 Spring이 자동으로 의존성을 주입한다.
장점: 필드 값을 초기화 후에도 변경할 수 있기 때문에, 동적으로 의존성을 설정할 수 있다.
단점: 스프링이 뜰 때만 초기화해주고 그 이후로는 바꾸지 않아서 평소에는 바꿀 일이 없다. 하지만 setter 주입을 사용하면 항상 메서드가 public이므로 의존성 객체를 언제나 변경 가능하다는 단점이 있다.
의존성 객체가 외부에서 변경되면 객체의 일관성을 보장하기 어려울 수 있다.
→ 생성자 주입으로 해결 가능❗
private final MemberRepository memberRepository;
@Autowired
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
의존성 객체를 생성자를 통해 주입한다.
이 때, final을 설정하여 생성자로 한번 생성되면 이후에는 상태를 변경할 수 없도록 보장할 수 있다.
하지만 위의 코드는 너무 번거롭다. 따라서 보다 간결하게 작성할 수 있는 방법에 대해 알아보겠다.
생성자가 하나일 때는 스프링으로 자동으로 의존성 주입을 해준다.
따라서 @Autowired 어노테이션 생략이 가능하다.
private final MemberRepository memberRepository;
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
그래도 코드가 번거롭다. 좀 더 간결하게 작성할 순 없을까?
→ final 과 @RequiredArgsConstructor 어노테이션을 사용하면 훨씬 간결하게 생성자 주입을 할 수 있다.
@RequiredArgsConstructor: final이 붙은 필드만 가지고 생성자를 만들어줌
@RequiredArgsConstructor
public class MemberService {
private final MemberRepository memberRepository;
}