앞에서 자동 의존 관계 주입 방법을 생성자를 통해 했는데, 사실 생성자 말고도 setter, 필드 주입, 일반 메서드 주입이 있다.
하지만 그나마 가끔 쓰는데 setter고 다른 방법들은 거의 안쓰니 생성자를 쓰자.
new로 생성할 때 딱 한번 호출됨이 보장된다.
@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;
}
}
생성자가 하나일 경우 @Autowired 생략 가능. 2개일 경우 어떤걸 사용해서 주입해야 하는지 알려줘야 하니까 넣어야 됨.
생성자는 불편, 필수일때 사용
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;
}
}
필드주입은 하게되면 순수자바로 어떻게 테스트해볼 수 있지 않기 때문에 무조건 스프링으로만 사용해야 되서 별로 안좋음. 거의 테스트할때만 쓴다고 함.
@Component
public class OrderServiceImpl implements OrderService {
@Autowired
private MemberRepository memberRepository;
@Autowired
private DiscountPolicy discountPolicy;
}
자동주입 옵션처리는 required=False로 하면 자동 주입할 대상이 없을 때 앱이 팅기는게 아니라 그냥 실행이 안되고, 다른 방법들도 있음.
@Nullable은 없다면 null반환, Optional은 자바 8부터 생긴것으로 없다면 empty.
Member는 bean에 등록된 클래스가 아니기 때문에 없는것이라고 에러가 뜬다.
근데 애초에 IDE에서 bean에 등록되어야 하는 클래스를 가지고 주입해야 한다고 오류가 뜸. 없다면 컨테이너에서 getBean으로 못 불러올 테니까
생성자가 좋은 이유는 생성자로 하기때문에 실행할 때 한번 실행되고 다시 실행되지 않아 불변 보장 및 순수자바코드로 작성할 때나 이 클래스는 DI로 어떤것이 필요하다~는걸 코드상 명확하게 표현할 수 있고, final 사용 가능으로 또다시 불변을 보장하기 때문.
setter같은걸로 하면 같은 기능을 할 수 있겠으나 가독성이 떨어짐.
여기만 해도 생성자로 정의함으로써 어떤 클래스가 필요한지 나타내주는 효과가 있다.
이건 lombook 사용 예시인데 lombook은 자바에서 getter, setter, tostring등 annotation만 붙이면 자동으로 해주는 애임.
기능 중 변수에 final을 붙여서 생성자에 붙이는 @RequiredArgsConstructor가 있고, 스프링에서 생성자가 하나일 시 @Component일 경우 자동으로 생성자 함수에 @Autowired를 붙여줌으로 궁합이 적절하다. 위 2개의 사진은 같은 코드다.
자동 컴포넌트 스캔에서 충돌했을 때의 대처방법. 위 경우가 그런 경우로, 지금까진 안쓰는 구체화 클래스는 그냥 @Component를 빼는 방식으로 했지만 일단 둘 다 annotation을 붙이고 어느걸 사용할지 정해줄 수 있다.
그냥 저렇게 사용했을 시 놀랍게도 변수명을 체크해본다. 가령 위에서 DiscountPolicy discountPolicy 하지 말고 DiscountPolicy rateDiscountPolicy를 하면 같은 이름의 것으로 따라가는 형태.
@Qualifier("~~")을 변수 타입 앞에 붙여서 할 수도 있고, 내가 원하는 클래스에 @Primary를 붙여서 사용할 수도 있다.
@Qualifier와 @Primary 둘다 잘 쓰기 때문에 코드의 간결성, 사용 빈도 등을 고려해서 팀과 상의하자.
참고로 @Qualifier를 사용할 경우, 이름을 미리 인터페이스로 지정해서 사용할 수 있음.
의도적으로 위 두 타입 다 필요할 때가 있는데, 그럴 땐 List나 Map에 등록해서 지정해줘서 사용할 수도 있다.
자동 빈 등록과 수동 빈 등록을 어떻게 조화롭게 사용해야 하나.
어플리케이션은 크게 업무 로직 빈과 기술 지원 빈으로 나눌 수 있는데, 업무 로직 빈은 실제 계산하고.. 하는 부분이고 기술 지원 빈은 DB에 연결하고 설정하고 하는 부분.
업무 로직 빈은 여러 번 유사한 패턴을 만드는 경우가 많으므로 자동으로 하게끔 하는게 좋고, 기술 지원 빈은 한번 정의하면 잘 수정할 일이 없고 한번 문제 터지면 어디서 터지는지조차 가늠하기 힘들기 때문에 전체적으로 어떻게 돌아가는지 한눈에 쉽게 볼 수 있도록 수동으로 해주는게 좋다. 가령 원래 AppConfig만 있을 땐 어떤 것이 빈에 등록되는지 AppConfig만 보면 알 수 있었지만 AutoAppConfig로 바꾼 뒤로는 클래스 여기저기 돌아다니며 @Component를 봐야 어떤게 등록된건지 알 수 있는 것처럼.
'CS > 김영한 스프링 강의' 카테고리의 다른 글
스프링 기본 - 섹션9. 빈 스코프 (0) | 2023.07.06 |
---|---|
스프링 기본 - 섹션8. 빈 생명주기 콜백 (0) | 2023.07.06 |
스프링 기본 - 섹션6. 컴포넌트 스캔 (0) | 2023.07.03 |
스프링 기본 - 섹션5. 싱글톤 컨테이너 (0) | 2023.07.03 |
스프링 기본 - 섹션4. 스프링 컨테이너와 스프링 빈 (0) | 2023.07.02 |