의존관계를 주입하는 방법에는 크게 네가지가 있다. 이 중 가장 많이 사용하고 권장되는 방법은 생성자 주입이다.
생성자 호출 시점에 딱 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;
}
}
스프링 빈에 OrderServiceImpl이 등록될 때 @Autowired가 붙은 생성자를 확인해서 MemberRepository와 DiscountPolicy를 스프링 컨테이너에서 꺼내 주입해준다.
불변, 필수 의존관계에 사용한다는 말은 곧 값이 변경되어서는 안되고 반드시 값이 할당되어야 한다는 것을 말한다.
@Component
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;
}
}
위의 코드에서처럼 생성자가 한개인 경우에는 @Autowired 어노테이션을 생략해도 된다.
Lombok 라이브러리의 @RequiredArgsConstructor 어노테이션을 사용하면 final이 붙은 필드를 모아 자동으로 생성자를 만들어준다.
@Component
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService{
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
//test
public MemberRepository getMemberRepository(){
return memberRepository;
}
}
선택적이고 변경가능성이 있는 의존관계에 사용한다. 생성자를 통해 주입받는 값이 필수값이라면 Setter로 주입받는 값은 선택적이다.
@Component
public class OrderServiceImpl implements OrderService{
private MemberRepository memberRepository;
private DiscountPolicy discountPolicy;
@Autowired
public void setMemberRepository(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
System.out.println("memberRepository = " + memberRepository);
}
@Autowired
public void setDiscountPolicy(DiscountPolicy discountPolicy) {
this.discountPolicy = discountPolicy;
System.out.println("discountPolicy = " + discountPolicy);
}
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
System.out.println("1 OrderServiceImpl 호출");
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
Setter를 통해서도 의존관계 주입이 가능하다. 위의 코드에서 보면 생성자와 setter가 동시에 사용된 것을 확인할 수 있다. 이 경우에는 OrderServiceImpl이 스프링 빈에 등록되면서 생성자를 먼저 호출하고 그 이후에 setter 주입을 받는다. 이 경우 생성자를 삭제하고 Setter 주입만 사용하면 된다.
코드가 간결하다는 장점이 있지만 외부에서 변경이 불가능하다는 단점이 있고 DI 프레임워크가 반드시 필요하다. 최근에는 필드 주입을 권장하지 않는다.
@Component
public class OrderServiceImpl implements OrderService{
@Autowired private MemberRepository memberRepository;
@Autowired private DiscountPolicy discountPolicy;
//test
public MemberRepository getMemberRepository(){
return memberRepository;
}
}
한번에 여러 필드를 주입받을 수 있다는 장점이 있지만 보통 생성자 주입이나 수정자 주입을 사용하기 때문에 일반적으로 잘 사용하지 않는다.
@Component
public class OrderServiceImpl implements OrderService{
private MemberRepository memberRepository;
private DiscountPolicy discountPolicy;
@Autowired
public void method(MemberRepository memberRepository, DiscountPolicy discountPolicy){
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
@Component
public class OrderServiceImpl implements OrderService{
private MemberRepository memberRepository;
private DiscountPolicy discountPolicy;
@Autowired(required = false)
public void setMemberRepository(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
@Autowired
public void setDiscountPolicy(DiscountPolicy discountPolicy) {
this.discountPolicy = discountPolicy;
}
}
기본적으로 @Autowired 어노테이션이 붙으면 의존관계 주입이 필요하다. 하지만 @Autowired(required = false)를 붙여 지정하면 선택적으로 주입할 수 있다.
스프링 빈에 등록되지 않은 Member 클래스를 주입받는 경우에는 옵션 처리를 해줄 수 있는데 @Nullable 어노테이션을 사용해 스프링빈에 등록된 객체가 없는 경우에는 null을 출력하거나 자바8의 문법인 Optional로 처리하는 방법이 있다.
@Autowired(required = false)
public void setBean(Member member){
System.out.println("member1 = " + member);
}
@Autowired
public void setBean2(@Nullable Member member){
System.out.println("member2 = " + member);
}
@Autowired
public void setBean3(Optional<Member> member){
System.out.println("member3 = " + member);
}
@Autowired(required = false) 인 경우에는 자동 주입할 대상이 없으면 수정자 메서드 자체가 호출이 되지 않아 아무런 값도 출력되지 않았고 @Nullable 어노테이션이 붙으면 null, Optional로 처리한 경우에는 Optional.empty가 출력된 것을 확인할 수 있다.