[Spring Framework] 생성자 주입을 사용해야하는 이유
🔍 의존성 주입(DI)
의존성 주입(Dependency Injection)은 객체 간의 의존 관계를 외부(IoC Container)로부터 주입받아 동적으로 의존관계를 성립시키는 방법이다. 스프링에서는 세 가지 주입 방법을 제공하지만, 그 중에서도 생성자 주입 방식을 권장한다.
의존성 주입 방법:
- 생성자 주입 (권장)
- Setter 주입
- 필드 주입
@Autowired 어노테이션
@Autowired 어노테이션은 스프링 컨테이너(IoC Container)에 등록된 빈(Bean) 중 타입이 일치하는 객체를 자동으로 주입해주는 어노테이션이다.
🏗️ 생성자 주입
생성자 주입은 생성자를 통해 의존 관계를 주입하는 방법이다.
1
2
3
4
5
6
7
8
9
10
11
@Service
public class UserService {
private UserRepository userRepository;
private MemberService memberService;
@Autowired
public UserService(UserRepository userRepository, MemberService memberService) {
this.userRepository = userRepository;
this.memberService = memberService;
}
}
생성자가 하나만 있을 경우, @Autowired를 생략할 수 있다:
1
2
3
4
5
6
7
8
9
10
@Service
public class UserService {
private UserRepository userRepository;
private MemberService memberService;
public UserService(UserRepository userRepository, MemberService memberService) {
this.userRepository = userRepository;
this.memberService = memberService;
}
}
🔧 Setter 주입
Setter 주입은 Setter 메서드를 통해 의존 관계를 주입하는 방법이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Service
public class UserService {
private UserRepository userRepository;
private MemberService memberService;
@Autowired
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Autowired
public void setMemberService(MemberService memberService) {
this.memberService = memberService;
}
}
🏷️ 필드 주입
필드 주입은 필드에 직접 의존 관계를 주입하는 방법이다.
1
2
3
4
5
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
}
하지만 이 방식은 권장되지 않는다.
- 순환 참조를 예방할 수 없다.
- 순환 참조 발생 시 런타임 단계에서야 오류를 잡아낼 수 있다.
- final을 사용할 수 없어 불변성을 보장받지 못한다.
- 객체의 불변성을 보장할 수 없어 런타임 중 객체가 변경될 가능성이 있다.
- 의존성을 숨긴다. (Dependency Hiding)
- 필드 주입은 Reflection API를 사용해 의존성이 외부로 노출된다.
- 테스트가 어렵다.
- 스프링 컨테이너 없이 순수한 자바 코드로 단위 테스트를 작성하기 어렵다.
🌟 생성자 주입을 권장하는 이유
- 📌 객체의 불변성 확보
- 생성자 주입은 객체 생성 시 1회만 호출되어 불변성을 보장한다.
- 변경 가능성이 없거나 반드시 객체 주입이 필요한 경우에 강제할 수 있다.
- 🧪 테스트 코드 작성의 용이성
- 순수한 자바 코드로 단위 테스트를 작성할 수 있다.
- 컴파일 시점에 객체를 주입받아 테스트 코드를 작성할 수 있다.
- 🔒 final 키워드 사용 및 Lombok과의 결합
- 필드에 final 키워드를 사용할 수 있어 컴파일 시점에 누락된 의존성을 확인할 수 있다.
- Lombok의
@RequiredArgsConstructor와 결합하여 코드를 간결하게 작성할 수 있다.
1 2 3 4 5 6
@Service @RequiredArgsConstructor public class UserService { private final UserRepository userRepository; private final MemberService memberService; }
- 🌱 스프링에 비침투적인 코드 작성
@Autowired같은 스프링 어노테이션을 사용하지 않아도 되어 프레임워크에 독립적인 코드를 작성할 수 있다.
- 🔄 순환 참조 에러 방지
- 애플리케이션 구동 시점(객체의 생성 시점)에 순환 참조 에러를 예방할 수 있다.
- 필드 주입은 애플리케이션이 구동된 후 호출 시점에 에러가 발생하지만, 생성자 주입은 시작 시점에 에러를 확인할 수 있다.
참고
Leave a comment