1) 생성자 주입
2) 수정자 주입(setter 주입)
3) 필드 주입
4) 일반 메서드 주입
생성자를 통해 의존관계를 주입하는 방법
@Autowired
생략 가능필드의 값을 변경하는 수정자 메서드를 통해 의존관계를 주입하는 방법
💻 스프링 컨테이너의 life cycle
- 스프링 빈 등록
- 의존관계(연관관계) 등록 -
@Autowired
필드에 바로 주입하는 방법
일반 메서드를 통해 주입하는 방법
💡 의존관계 자동 주입은 스프링 컨테이너가 관리하는 스프링 빈이어야 동작한다. 스프링 빈이 아닌 클래스에서 @Autowired
는 동작하지 않는다.
👀 주입할 스프링 빈이 없어도 동작해야 할 때,
@Autowired
를 사용하면 required
옵션의 기본값이 ture로 되어있기 때문에 자동 주입 대상이 없으면 오류가 발생한다.
1) @Autowired(required=false)
: 자동 주입할 대상이 없으면 수정자 메서드 호출 X
2) org.springframework.lang.@Nullable
: 자동 주입할 대상이 없으면 null이 입력됨
3) Optional<>
: 자동 주입할 대상이 없으면 Optional.empty
가 입력됨
static class TestBean {
@Autowired(required = false)
public void setNoBean1(Member noBean1) {
System.out.println("noBean1 = " + noBean1);
}
@Autowired
public void setNoBean2(@Nullable Member noBean2) {
System.out.println("noBean2 = " + noBean2);
}
@Autowired
public void setNoBean3(Optional<Member> noBean3) {
System.out.println("noBean3 = " + noBean3);
}
}
실행 결과 : ApplicationContext를 생성한 결과!
setNoBean1
메서드 자체가 호출되지 않았음을 알 수 있다.
final
키워드final
로 생성자에서 값이 설정되지 않은 에러를 컴파일 시점에 파악할 수 있다.✅롬복 라이브러리
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
}
@RequiredArgsConstructor
기능을 사용하면 final이 붙은 필드들을 주입하는 생성자를 자동으로 만들어 준다.@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
}
💡 롬복이 자바의 애노테이션 프로세서라는 기능을 이용해 컴파일 시점에 생성자 코드를 자동으로 생성해준다.
@Autowired
는 타입으로 빈을 조회하기 때문에 타입으로 조회된 빈이 2개 이상일 때 문제가 발생하게 된다.
@Autowired
필드명 매칭@Autowired
private DiscountPolicy rateDiscountPolicy
스프링 빈에
DiscountPolicy
의 하위 타입으로RateDiscountPolicy
와FixDiscountPolicy
가 있기 때문에 두 개의 빈이 조회된다. 이때 필드명이rateDiscountPolicy
일 경우 두 개의 타입 중RateDiscountPolicy
를 선택해 의존관계를 주입한다.
@Qualifier
추가 구분자를 붙여주는 방법
@Qualifier
간 매칭NoSuchBeanDefinitionException
예외 발생@Component
@Qualifier("mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy {}
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, @Qualifier("mainDiscountPolicy") DiscountPolicy
discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
@Primary
우선순위를 부여하여 우선권을 가지는 빈 선택
rateDiscountPolicy
에게 우선권 부여@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy {}
@Component
public class FixDiscountPolicy implements DiscountPolicy {}
💻
@Primary
와@Qualifier
활용메인 데이터베이스의 커넥션을 획득하는 스프링 빈의 경우
@Primary
를 적용하여 조회하는 곳에서 수정없이 편리하게 조회할 수 있도록 하고, 서브 데이터베이스의 커넥션을 획득하는 스프링 빈의 경우@Qualifier
를 지정해서 명시적으로 획득하는 방식으로 사용한다.
💻 우선순위
@Primary
는 기본값처럼 동작하고,@Qualifier
는 매우 상세하기 동작하기 때문에@Qualifier
에게 우선권이 부여된다.
@Qualifier
를 사용하는 애노테이션 만들기위의 @Qualifier
애노테이션을 사용하는 애노테이션을 만들어보자.
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER,
ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Qualifier("mainDiscountPolicy")
public @interface MainDiscountPolicy {}
@Component
@MainDiscountPolicy
public class RateDiscountPolicy implements DiscountPolicy {}
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, @MainDiscountPolicy DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
static class DiscountService {
private final Map<String, DiscountPolicy> policyMap;
private final List<DiscountPolicy> policies;
@Autowired
public DiscountService(Map<String, DiscountPolicy> policyMap, List<DiscountPolicy> policies) {
this.policyMap = policyMap;
this.policies = policies;
}
}
💻
DiscountService
의 생성자가 호출되면policyMap
과policies
가 자동 생성되어 주입된다. 이 맵과 리스트에는 스프링 빈에 저장된DiscountPolicy
타입의 빈들이 들어간다.