[Spring 기본] 6. 의존관계 자동 주입

heyhey·2023년 2월 2일
0

Spring

목록 보기
15/23

의존관계 주입 방법은 크게 4가지가 있다.

생성자 주입 (지금까지의 예제)

  • 생성자 호출시점에 딱 1번만 호출되는게 보장된다.
  • 불변,필수의 의존관계에서 사용된다.
  • 생성자가 딱 1개만 있으면 @Autowired를 생략해도 자동 주입된다.

수정자 주입 (setter)

  • setter라 불리는 필드의 값을 변경하는 수정자 메서드를 통해서 의존관계를 주입하는 방법
  • 선택, 변경 가능성 있는 의존관계에 사용된다.

필드 주입

  • 필드에 바로 주입하는 방법
@Autowired
private MemberRepository memberRepository;

(이게 된다고?)
코드가 간결해서 좋아보이지만, 외부에서 변경이 불가능해서 테스트가 어렵다
사용하지 말자
테스트 코드에서는 사용해도 무방하다.

일반 메서드 주입

  • 일반 메서드를 통해 주입받을 수도 있다.
  • 수정자 주입이랑 크게 다르진 않다.
  • 잘 안사용한다.

의존관계 자동 주입은 스프링 컨테이너가 관리하는 스프링 빈이어야 한다.


아래는 스프링 빈이 아닌 클래스를 자동 주입하려고 할 때 에러가 나지 않게 하는 작업이다.

옵션 처리

주입할 스프링 빈이 없어도 동작하게 해야할 때가 있다.
@Autowiredrequired:true 가 되어있어서 주입대상이 없으면 오류가 난다.

자동 주입 대상을 옵션으로 처리한다.

  • @Autowired(required=false) : 자동 주입할 대상이 없으면 수정자 메서드 자체가 호출 안됨

  • @Nullable : 자동 주입할 대상이 없으면 null이 입력됨

@Autowired
public void setNoBean2(@Nullable Member member) {}
  • Optional<> : 자동 주입할 대상이 없으면 Optional.empty 가 입력됨
@Autowired
public void setNoBean3(Optional<Member> member) {}

요즘은 생성자 주입을 권장하는 편인다.

  • 의존관계 주입은 한번 일어나면 변경할 일이 잘 없다. (차라리 불변해야 한다.)
  • 생성자 주입은 객체 생성시 딱 1회만 호출되기 때문에 불변되게 설계된다.

final 키워드

생성자 주입을 사용하면 필드에 final 키워드를 생성할 수 있다.
이 기능으로 생성자에서 값이 설정되지 않으면 컴파일 시점에 막아준다.
(웬만하면 다 final 이겠다 그럼)

롬복

롬복을 이용해서 수 많은 작업들이 줄어들게 된다. 생성자 주입도 마찬가지다.

설치

build.gradle 파일에 롬복을 추가한다.


configurations {
  compileOnly {
      extendsFrom annotationProcessor
  } 
}
dependencies {
    //lombok 라이브러리 추가 시작
    compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok'
    testCompileOnly 'org.projectlombok:lombok' testAnnotationProcessor 'org.projectlombok:lombok' 
}
  • dependencies 와 configurations 에서 롭복 관련 환경 설정들을 추가한다.
  • Preferences(윈도우 File Settings) => plugin => lombok 검색 설치 실행
  • Preferences Annotation Processors 검색 => Enable annotation processing 체크

적용

@Component
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {
    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;
}

@RequiredArgsConstructor 기능을 사용하면 final 이 붙은 필드를 모아서 생성자를 자동으로 생성해준다.

조회 빈이 2개 이상일 때 ?

@Autowired
private DiscountPolicy discountPolicy

만약 FixDiscountPolicy , RateDiscountPolicy를 둘다 스프링 빈으로 등록한다면 어떻게 될까?

=> NoUniqueBeanDefinitionException 오류가 발생한다.
하나의 빈을 기대했는데 fixDiscountPolicy , rateDiscountPolicy 2개가 발견되었다 라고 한다.

해결방법


Autowired 필드명 변경

  • @Autowired는 타입 매칭을 시도하고, 여러 빈이 있다면 필드 이름, 파라미터 이름으로 빈 이름을 매칭한다.
  • 타입이 동일한게 있다 => 이름으로 매칭

discountPolicy => rateDiscountPolicy

@Autowired
private DiscountPolicy rateDiscountPolicy

Qualifier

  • @Qualifier는 추가 구분자를 붙여주는 방법이다.
  • 추가 방법을 제공할 뿐이지 빈 이름을 변경하는 것은 아니다.
  • @Qualifier끼리 매칭된다.

빈 등록시에 @Quilifier 를 적어준다.

@Autowired
@Qualifier("mainDiscountPolicy")
private DiscountPolicy discountPolicy

생성자에서 주입시 @Qualifier 에 등록한 이름을 적어준다.

@Autowired
public OrderServiceImpl(
  MemberRepository memberRepository, 
  @Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy
) {
  this.memberRepository = memberRepository;
  this.discountPolicy = discountPolicy;
}

Primary

- @Primary 는 우선순위를 정하는 방법이다.

  • 여러빈이 매칭되면 @Primary가 우선권을 갖는다.
@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy {}

@Qualifier("mainDiscountPolicy") 이렇게 문자를 적으면 컴파일시 타입체크가 되지 않는다.
애노테이션을 직접 만들어서 문자열을 바꿔보자

애노테이션 만들기

@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;
}

자동, 수동의 올바른 실무 운영 기준

스프링이 나오고 시간이 갈 수록 점점 자동을 선호하는 추세다

  • 그러면 수동 빈 등록은 언제 사용하면 좋을까?

애플리케이션에 광범위하게 영향을 미치는 기술 지원 객체는 수동 빈으로 등록해서 딱! 설정 정보에 바로 나타나게 하는 것이 유지보수 하기 좋다.
편리한 자동 기능을 기본으로 사용하자
직접 등록하는 기술 지원 객체는 수동 등록
다형성을 적극 활용하는 비즈니스 로직은 수동 등록을 고민해보자

profile
주경야독

0개의 댓글