✅ @Nullable ✅ @Qualifier ✅ @Primary
생성자를 통해 의존관계를 주입하는 방법으로, 생성자 호출시점에 딱 1번만 호출되는 것이 보장된다.
불변
해야 하거나,필수
적인 의존관계에 사용
@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;
}
}
👉 생성자가 딱 1개만 있으면 @Autowired를 생략해도 자동 주입 된다. (스프링 빈에만 해당)
setter라 불리는 필드의 값을 변경하는 수정자 메서드를 통해서 의존관계를 주입하는 방법
선택
,변경
가능성이 있는 의존관계에 사용
@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
private MemberRepository memberRepository;
@Autowired
private DiscountPolicy discountPolicy;
일반 메서드를 통해서 주입 (안씀)
@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;
}
}
대부분(
불변
,필수
의존관계) 생성자 주입 방법을 사용하고 예외적인 경우(선택
,변경
의존관계)에 수정자(setter) 주입을 사용한다.
final
키워드를 사용할 수 있다. 그래서 생성자에서 혹시라도 값이 설정되지 않는 오류를 컴파일 시점에 막아준다.자동 주입할 대상이 없으면 수정자 메서드 자체가 호출 안됨
// 호출 안됨
@Autowired(required = false)
public void setNoBean1(Member member) {
System.out.println("setNoBean1 = " + member);
}
자동 주입할 대상이 없으면 null이 입력된다.
// null 호출
@Autowired
public void setNoBean2(@Nullable Member member) {
System.out.println("setNoBean2 = " + member);
}
자동 주입할 대상이 없으면 Optional.empty 가 입력된다.
// Optional.empty 호출
@Autowired(required = false)
public void setNoBean3(Optional<Member> member) {
System.out.println("setNoBean3 = " + member);
}
@Component
public class FixDiscountPolicy implements DiscountPolicy {}
@Component
public class RateDiscountPolicy implements DiscountPolicy {}
그리고 의존관계 자동 주입을 실행하면
@Autowired
private DiscountPolicy discountPolicy
NoUniqueBeanDefinitionException
오류가 발생한다.
하나의 빈을 기대했는데 fixDiscountPolicy , rateDiscountPolicy 2개가 존재하기 때문이다.
필드 명을 변경하는 방법
기존 코드
@Autowired
private DiscountPolicy discountPolicy
필드 명을 빈 이름으로 변경
@Autowired
private DiscountPolicy rateDiscountPolicy
추가 구분자를 붙여주는 방법
1) 빈 등록시 @Qualifier를 붙여 주거나
@Component
@Qualifier("mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy {}
@Component
@Qualifier("fixDiscountPolicy")
public class FixDiscountPolicy implements DiscountPolicy {}
2) 주입시에 @Qualifier를 붙여주고 등록한 이름을 적어준다.
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, @Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
우선순위를 정하는 방법으로, @Autowired 시에 여러 빈이 매칭되면 @Primary 가 우선권을 가진다.
@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy {}
@Component
public class FixDiscountPolicy implements DiscountPolicy {}
코드에서 자주 사용하는 메인 데이터베이스의 커넥션을 획득하는 스프링 빈이 있고,
특별한 기능으로 가끔 사용하는 서브 데이터베이스의 커넥션을 획득하는 스프링 빈이 있다고 생각해보자.
@Primary
를 적용해서 조회하는 곳에서 @Qualifier 지정 없이 편리하게 조회@Qualifier
를 지정해서 명시적으로 획득 하는 방식으로 사용하면 코드를 깔끔하게 유지할 수 있다.물론 이때 메인 데이터베이스의 스프링 빈을 등록할 때 @Qualifier 를 지정해주는 것은 상관없다.