🧐강의🧐
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard
- 다양한 의존 관계 주입 방법
- 생성자 주입
- 수정자 주입
- 필드 주입 (권장 X)
- 일반 메서드 주입
- 항상 생성자 주입 선택 + 필요 시 수정자 주입 선택
1️⃣ 생성자 주입
☑️ 생성자를 통해 의존 관계 주입하기
· ⭐ 특징
- 생성자 호출 시점에 한 번만 호출
- "불변, 필수" 의존 관계에 사용
- 불변 : 바뀌지 않는 코드
- 필수 : final 변수 → 대응값 존재해야 함
- ⭐ 생성자가 1개만 있으면, @Autowired 생략 가능 (스프링 빈만 해당)
· OrderServiceImpl
...
@Component
public class OrderServiceImpl implements OrderService{
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
...
}
2️⃣ 수정자 주입
☑️ 수정자 메서드 (setter 필드 값 변경) 를 통해 의존 관계 주입하기
· 특징
- "선택, 변경" 가능성이 있는 의존 관계에 사용
- 선택 : @Autowired(required = false)
- 변경 : 외부 호출
· OrderServiceImpl
...
@Component
public class OrderServiceImpl implements OrderService{
private MemberRepository memberRepository;
private DiscountPolicy discountPolicy;
@Autowired
public void setMemberRepository(MemberRepository memberRepository) {
this.memberRepository = memberRepository
}
@Autowired
public void setDiscountPolicy(DiscountPolicy discountPolicy) {
this.discountPolicy = discountPolicy;
}
...
}
참고
- @Autowired 는 주입할 대상이 없으면 오류 발생 → @Autowired(required = false) 지정
- 자바빈 프로퍼티, 자바에서는 setXxx, getXxx 메서드를 통해 값을 읽거나 수정 (필드값 변경X)
3️⃣ 필드 주입
☑️ 필드에 바로 의존 관계 주입하기
· 특징
- 간결한 코드
- 외부에서 변경 불가 → 테스트하기 힘든 환경
- DI 컨테이너가 없으면 동작 불가
- 사용하는 경우 : 애플리케이션의 실제 코드와 관계 없는 테스트 코드, @Configuration (스프링 설정)
· OrderServiceImpl
...
@Component
public class OrderServiceImpl implements OrderService{
@Autowired private MemberRepository memberRepository;
@Autowired private DiscountPolicy discountPolicy;
...
}
참고
- @Autowired 는 @SpringBootTest 처럼 스프링 컨테이너를 테스트에 통합한 경우에만 사용 가능
4️⃣ 일반 메서드 주입
☑️ 일반 메서드를 통해 의존 관계 주입하기
· 특징
- 한 번에 여러 필드 주입 가능
- 일반적으로 잘 사용하지 않음
· OrderServiceImpl
...
@Component
public class OrderServiceImpl implements OrderService{
private MemberRepository memberRepository;
private DiscountPolicy discountPolicy;
@Autowired
public void init(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
...
}
참고
- 스프링 컨테이너가 관리하는 스프링 빈이어야 의존 관계가 자동으로 주입됨
🚨 문제 상황 🚨
수정자 의존 관계인 경우
· OrderServiceImpl
...
@Component
public class OrderServiceImpl implements OrderService{
private MemberRepository memberRepository;
private DiscountPolicy discountPolicy;
@Autowired
public void setMemberRepository(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
@Autowired
public void setDiscountPolicy(DiscountPolicy discountPolicy) {
this.discountPolicy = discountPolicy;
}
...
}
· OrderServiceImplTest
class OrderServiceImplTest {
@Test
void createOrder() {
OrderServiceImpl orderService = new OrderServiceImpl();
Order order = orderService.createOrder(1L, "itemA", 10000);
}
}
· 테스트 결과
➡️ NPE (Null Point Exception) 발생 : memberRepository, discountPolicy 모두 의존 관계 누락
💡 해결 방법 💡
생성자 주입 & final 키워드
· OrderServiceImpl
☑️ 생성자 주입 사용 시 final 키워드 사용 : 생성자에 값이 설정되지 않을 시, 컴파일 시점에 오류 방지
...
@Component
public class OrderServiceImpl implements OrderService{
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
...
}
· OrderServiceImplTest
...
class OrderServiceImplTest {
@Test
void createOrder() {
MemoryMemberRepository memberRepository = new MemoryMemberRepository();
memberRepository.save(new Member(1L, "name", Grade.VIP));
OrderServiceImpl orderService = new OrderServiceImpl(new MemoryMemberRepository(), new FixDiscountPolicy());
Order order = orderService.createOrder(1L, "itemA", 10000);
org.assertj.core.api.Assertions.assertThat(order.getDiscountPrice()).isEqualTo(1000);
}
}
· 테스트 결과
참고
- 생성자 주입을 제외한 나머지 주입 방식은 모두 생성자 이후에 호출되므로, 필드에 final 키워드 사용 불가
- 수정자 주입 사용 시, setXxx 메서드를 public 으로 열어두어야 함 → 좋은 설계 방법 X
- 생성자 주입 사용 시, 객체를 생성할 때 1번만 호출되므로 불변하게 설계 가능
'Spring > 스프링 핵심 원리 - 기본편' 카테고리의 다른 글
[의존 관계 자동 주입] Lombok 적용하는 방법 (0) | 2023.12.20 |
---|---|
[의존 관계 자동 주입] 자동 주입 대상 옵션으로 처리하기 (0) | 2023.12.19 |
[컴포넌트 스캔] 필터 - includeFilters, excludeFilters (2) | 2023.12.07 |
[컴포넌트 스캔] 기본 스캔 대상 (1) | 2023.12.07 |
[컴포넌트 스캔] @Component, @Autowired - 의존 관계 자동 주입 (0) | 2023.12.05 |