ComponentScan 할 때 OrderService가 @Component 붙어있으니 컨테이너에 등록을 해줄텐데 그 때 생성자가 호출이 되고 생성자를 호출할 때 @Autowired가 있네 하면서 스프링 컨테이너 에서 MemberRepository랑 DiscountPolicy 이 두 스프링빈을 꺼내서 딱 주입해줌
getter setter로 접근하게 해놓으면 에러가 발생 할 확률이 높아서 getter setter로 접근하게 하면 안됨
참고로 생성자가 한 개만 있으면 @Autowired 생략가능함
위와 같이 setter로도 의존 관계 주입이 가능
자바에서는 과거부터 필드의 값을 직접 변경하지 않고, setXxx, getXxx 라는
메서드를 통해서 값을 읽거나 수정하는 규칙을 만들었는데, 그것이 자바빈 프로퍼티 규약이다
class Data {
private int age;
//age를 수정하기 위해서는 setAge()를 이용해야함
public void setAge(int age) {
this.age = age;
}
//age를 읽기 위해서는 getAge()를 이용해야함
public int getAge() {
return age;
}
}
이렇게 필드값에 바로 @Autowired하는 방법은 사용하지 말자..!
test에서는 써도 괜찮다고 하는듯
말 그대로 그냥 일반함수를 따로 만들어서 의존관계를 주입하는 방법임
주입 할 스프링 빈이 없을 때 돌리고 싶으면 아래와 같이 세가지 방법을 사용하면 된다
위처럼 테스트 만들어서 테스트 돌려보면
아래와 같이 나옴
현재 저거 세개 다 주입대상이 없는 상황인데
첫 번째 : required=false: 자동 주입할 대상이 없으면 수정자 메서드 자체가 호출 안됨
두 번째 : org.springframework.lang.@Nullable : 자동 주입할 대상이 없으면 null이 입력된다.
세 번째 :Optional<> : 자동 주입할 대상이 없으면 Optional.empty 가 입력된다
만약에 OrderServiceImpl을 잘 만들었는지 테스트 해보고 싶어서
아래와 같이 테스트를 만들고 테스트를 돌려보면 에러가 난다
왜냐면 OrderServiceImpl에 가보면
저 두개 값을 세팅을 해줘야함
즉 저 두개를 주입을 해줘야 하는건데 테스트 짤 때는 뭔가 이녀석의 의존관계가 어떻게 됐더라?? 이런 상황이 많이 발생함
근데 여기서 저기 지금은 setter로 주입하는 상황인데 setter주입 없애버리고 아래 사진처럼 다시 생성자살려서 생성자 주입으로 바꿔주면
테스트 짤 때 아래처럼 빨간줄로 에러를 띄어줌
이제 저 컴파일에러를 보고 임의로 아래처럼 대충 만들어서 넣어주면 됨
또 좋은점은 final 키워드를 멕일 수 있음
즉 final을 붙이면 생성자가 호출될 때 한 번 정해지고 그 뒤로는 안바뀐다는 말
다른 곳 에서는 못바꿈스
참고로 생성자 주입방식만 final 키워드를 사용할 수 있다
springboot 만들 때 추가하면 되고 사용하면 아래와 같은 장점이 있음
@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;
}
}
이런 코드에 @RequiredArgsConstructor를 붙여주면
@Component
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
}
위와 같이 생성자를 내가 따로 안만들어도 알아서 만들어줌
@Autowired는 타입으로 조회를 함
타입이 1개면 그냥 상관이 없는데 같은 타입이 2개면 어떻게?
현재 스프링 빈에는 아래와 같이 등록이 되어있을텐데
@Autowired는 타입이 여러개인 스프링 빈이 있으면 필드명(변수)으로 추가적으로 찾아서 맞춰줌
DiscountPolicy(인터페이스) - FixDiscountPolicy(구현체)
DiscountPolicy(인터페이스) - RateDiscountPolicy(구현체)
따라서 아래와 같이 필드명을 구체적으로 구현체이름으로 바꿔주면 된다
pass
현재 스프링 빈에는 아래와 같이 등록이 되어있을텐데
DiscountPolicy(인터페이스) - FixDiscountPolicy(구현체)
DiscountPolicy(인터페이스) - RateDiscountPolicy(구현체)
주입을 할 때 우선순위를 정해줄 수 있음
위처럼 해주면 RateDiscountPolicy 구현체가 우선순위를 가져간다
저렇게 직접 DiscountService.class를 넣어주면 바로 ComponentScan 해서 컨테이너에 등록이 된다고 하는데 애초에 DiscountService를 왜 컨테이너에 등록해야하지?