4가지 의존관계 주입 방법이 있다.
생성자를 통해서 의존 관계를 주입 받는 방법이다.
생성자에 @Autowired를 하면 스프링 컨테이너에 @Component로 등록된 빈에서 생성자에 필요한 빈들을 주입한다.
특징
생성자 호출 시점에 딱 1번만 호출되는 것이 보장된다.
불변과 필수
의존 관계에 사용된다.
생성자가 1개만 존재하는 경우에는 @Autowired를 생략해도 자동 주입 된다.
NullPointerException
을 방지할 수 있다.
주입받을 필드를 final
로 선언 가능하다.
@Component
public class CoffeeService {
private final MemberRepository memberRepository;
private final CoffeeRepository coffeeRepository;
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, CoffeeRepository coffeeRepository) {
this.memberRepository = memberRepository;
this.coffeeRepository = coffeeRepository;
}
}
setter라 불리는 필드의 값을 변경하는 수정자 메서드를 통해서 의존 관계를 주입하는 방법이다.
특징
선택과 변경 가능성이 있는 의존 관계에 사용된다.
자바빈 프로퍼티 규약의 수정자 메서드 방식을 사용하는 방법이다.
@Component
public class CoffeeService {
private final MemberRepository memberRepository;
private final CoffeeRepository coffeeRepository;
@Autowired
public void setMemberRepository(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
@Autowired
public void setCoffeeRepository(CoffeeRepository coffeeRepository) {
this.coffeeRepository = coffeeRepository;
}
}
생성자 주입과 차이점은 생성자 대신 set필드명 메서드를 생성하여 의존 관계를 주입하게 된다.
수정자의 경우 @Autowired
를 입력하지 않으면 실행이 되지 않는다.
생성자가 1개일 때 @Autowired가 없어도 작동이 된다.
스프링이 해당 클래스 객체를 생성하여 빈에 넣어야하는데 생성할 때 생성자를 부를 수 밖에 없게 된다.
그렇기 때문에 빈을 등록하면서 의존 관계 주입도 같이 발생하게 되기 때문이다.
필드에 @Autowired
붙여서 바로 주입하는 방법이다.
특징
코드가 간결해서 예전에 많이 사용된 방식이지만, 외부에서 변경이 불가능하여 테스트하기 힘들다는 단점이 있다.
DI 프레임워크가 없으면 아무것도 할 수 없다.
실제 코드와 상관 없는 특정 테스트를 하고 싶을 때 사용할 수 있다.
하지만 정상적으로 작동되게 하려면 결국 setter가 필요해서 수정자 주입을 사용하는게 더 편리해진다.
@Component
public class CoffeeService {
@Autowired
private final MemberRepository memberRepository;
@Autowired
private final CoffeeRepository coffeeRepository;
}
일반 메서드를 사용해 주입하는 방법이다.
특징
한번에 여러 필드를 주입 받을 수 있다.
일반적으로 사용되지 않는다.
주입할 스프링 빈이 없을 때 동작해야하는 경우가 있다.
@Autowired
만 사용하는 경우 required 옵션 기본값인 true가 사용되어 자동 주입 대상이 없으면 오류가 발생하는 경우가 있을 수 있다.
스프링 빈을 옵셔널하게 해둔 상태에서 등록이 되지 않고, 기본 로직으로 동작하게 하는 경우
자동 주입 대상 옵션 처리 방법
null
이 입력된다.Optional.empty
가 입력된다.과거에는 수정자, 필드 주입을 많이 사용했지만, 최근에는 대부분 생성자 주입 사용을 권장한다.
생성자 주입 사용 이유
불변
의존 관계 주입
은 처음 애플리케이션이 실행될 때 대부분 정해지고 종료 전까지 변경되지 않고 변경되어서는 안된다.
수정자 주입
같은 경우에는 이름 메서드를 public으로 열어두어 변경이 가능하기 때문에 적합하지 않다.
(누군가 실수로 변경할 수도 있고, 애초에 변경하면 안되는 메서드가 변경할 수 있게 설계하는 것은 좋은 방법이 아니다.
생성자 주입
은 객체를 생성할 때 최초로 1번만 호출되고 그 이후에는 다시는 호출되는 일이 없기 때문에 불변하게 설계할 수 있다.
누락
의존관계 주입
이 누락되었기 때문에 발생한다.생성자 주입
을 사용하면 주입 데이터 누락 시 컴파일 오류가 발생한다.final 키워드 사용 가능
final
키워드를 사용할 수 있다.java: variable (데이터 이름) might not have been initialized
final
키워드를 사용할 수 없다.순환 참조
순환 참조를 방지할 수 있다.
개발하다보면 여러 컴포넌트 간에 의존성이 생기게 된다. (A → B를 참조하고, B → A를 참조)
필드 주입과 수정자 주입은 빈이 생성된 후에 참조를 하기 때문에 애플리케이션이 어떠한 오류와 경고 없이 구동된다.
실제 코드가 호출될 때까지 문제를 알 수 없다.
생성자를 통해 주입하게되면 BeanCurrentlyInCreationException
이 발생하게 된다.
의존관계 설정이 되지 않으면 객체생성이 불가능하다.
의존성 주입이 필요한 필드를 final 로 선언 가능하다.
(스프링에서) 순환참조 감지가 가능하다.
테스트 코드 작성 용이하다.
수정자 주입이 필요한 경우가 있을 수 있지만 옵션이 필요할 때만 선택하면 된다.