@ComponentScan을 통해 패키지 스캔중 @Component가 있으면 스프링빈 등록이 되고,
@Autowired가 있는경우에 스프링빈으로 등록이 된것을 찾아 의존관계 주입을 한다.
여기서 의존관계 주입 방법이 몇가지 있다.
1. 생성자 주입
- 생성자를 통하여 의존 관계를 주입
- 생성자 호출 시점 한번만 호출 되는것을 보장
- final 키워드 사용가능하여 null 방지 가능
( final : 값이 무조건! 초기화 되어야 한다는걸 의미 )
- 불변, 필수 의존관계에 사용
@Component
public class OrderServiceImpl implement OrderService{
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
}
※생성자가 위와 같이 하나인 경우에는 @Autowired 생략가능 ( 스프링이 어노테이션 자동으로 해준다. )
2. 수정자 주입 ( setter 주입 )
- setter를 통해서 의존관계 주입
- 선택, 변경 가능성있는 경우 사용
3. 필드 주입
- 필드에 바로 주입 ( 굉장히 깔끔하다. )
- 하지만, 외부에서 변경이 불가능해 @Test하기 힘든 단점
- 사용하지 말자
@Component
public class OrderServiceImpl implements OrderService {
@Autowired
private MemberRepository memberRepository;
@Autowired
private DiscountPolicy discountPolicy;
}
@Autowired는 스프링 기술이다. 그래서 @Test환경과 같이 순수 자바코드로 돌아가는 상황에선
필드 주입은 좋지 않다.
※@Autowired는 스프링 컨테이너가 관리하는 스프링 빈 내에서만 동작한다는거 잊지말자.
만약 스프링 빈으로 등록되지 않은걸 의존 관계로 주입하려하면 어떻게 될까?
스프링에서 기본으로 required 옵션이 true로 되어있어서 등록되지 않은 스프링 빈인 경우 오류가 발생
자동 주입 처리 방법은 세가지가 있다.
1. required=false
- 대상이 없는 경우 호출 안됨
2. @Nullable
- 대상이 없는 경우 null 반환
3. Optional<>
- 대상이 없는경우 empty 반환
하지만, 생성자 주입을 선택하자!
왜?
- 의존관계는 변경할 일이 없다.
- 변경이 가능하게 열어 두는것은 좋은 설계 방법이 아니다. ( public X! )
- 위에서 언급했듯이 final 키워드를 이용 할 수 있다.
롬복이란
@Getter, @Setter 와 같이 어노테이션만 설정하면, 프로퍼티 접근법 코드를 작성하지 않아도 생성된다.
또,@RequiredArgsConstructor와 같이 어마무시한 기능을 제공하는데
해당 어노테이션은 아래와 같이 final이 붙은 필드에를 생성자를 만들어서 의존 관계 주입을 받는다.
@Component
@RequiredArgsConstructor
public class OrderServiceImpl implement OrederService{
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
}
ctrl + f12 해보면 생성자가 있고 매개변수도 final에 붙은 필드의 이름으로 만들어져 있다.
생성자로 받아야되는게 많은 경우 아주 효율적
@Autowired는 타입으로 조회를 한다.
- 같은 타입을 찾는다.
- 근데 2개이상이면 같은 이름을 가진 빈을 찾아서 주입한다.
만약 같은 타입이 여러개가 있으면??
NoUniqueBeanDefinitionException 오류 발생!!
이럴때 몇가지 방법이 있다.
1. @Autowired 필드 명 매칭
2. @Qualifier @Qualifier끼리 매칭 빈 이름 매칭
- 추가 구분자를 붙혀준다. ( 빈 이름 변경하는것 아님 )
@Component
@Qualifier("mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy {}
@Component
@Qualifier("fixDiscountPolicy")
public class FixDiscountPolicy implements DiscountPolicy {}
@Autowired
public OrderServiceImpl(
MemberRepository memberRepository,
@Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
위 코드 설명
만약 @Qualifier를 사용하지 않았다면 두개의 @Component가 DiscountPolicy타입으로 스프링 빈이 등록이되고, OrderServiceImpl에서 의존관계 주입시 NoUniqueBeanDefinitionException 오류가 발생한다.
하지만! @Qualifier에 구분자를 주어서 의존관계 주입시 같은 이름을 가진 즉, mainDiscountPolicy인
RateDiscountPolicy가 주입이 된다.
3. @Primary 사용
@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy {}
@Component
public class FixDiscountPolicy implements DiscountPolicy {}
@Autowired
public OrderServiceImpl( MemberRepository memberRepository, DiscountPolicy discountPolicy ) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
위 코드 설명
@Primary를 사용한 스프링 빈을 주입해준다.
간단하다.
어떤게 더 우선순위를 가질까?
언제나 구체적인게 더 우선순위를 가진다.
무슨말이냐?
@Qualifier는 구분자도 쓰고 세세한 설정이 필요하기 때문에 우선순위가 더 높다.
그럼 어떤걸 쓰는게 좋을까?
@Qualifier는 구분자를 서로 넣어줘야하고, 할게 많다. 오타날 수도 있다. 코드가 길어진다.
꼭 써야하는경우엔 @Primary를 쓰자.
※ctrl + b누르면 사용되고 있는 곳을 확인 할 수 있다.
- 김영한 스프링 강의를 들으면 정리한 내용
'공부 > 과거 자료' 카테고리의 다른 글
[Spring MVC] 웹 애플리케이션 이해 (0) | 2022.07.19 |
---|---|
[Java] 클래스메서드, 인스턴스메서드 (0) | 2022.07.14 |
[Spring] ComponentScan (0) | 2022.07.14 |
[Spring] 싱글톤 (0) | 2022.07.13 |
[Spring] @Configuration, @Bean, Application (0) | 2022.07.13 |