스프링 의존성 주입

seungho choi·2022년 5월 31일
0

인프런 영한님의 스프링 핵심 원리 - 기본편을 보고 모르는 내용만 정리한 글이니 두서가 없을 수 있습니다!

조회 빈이 2개 이상 일때

@Component
public class FixDiscountPolicy implements DiscountPolicy {}

@Component
public class RateDiscountPolicy implements DiscountPolicy {}

만약에 이런 코드가 있다고 하고 DiscountPolicy 으로 의존성 주입을 받는 코드가 있다면 어떤식으로 동작할까?

의존성 주입은 타입으로 조회 해 의존성을 주입한다.

타입으로 조회하기 때문에, 마치 다음 코드와 유사하게 작동할 것이다. (실제로는 이것보다 복잡하다고 한다.)

ac.getBean(DiscountPolicy.class); // 이런 방식일껄?

실제로 DiscountPolicy의 타입인 의존성 주입을 받아야 하는 코드가 있으면

스프링 컨테이너 에서는 DiscountPolicy의 자식 타입인FixDiscountPolicyRateDiscountPolicy 빈이 두개가 등록 되어 있기 때문에 NoUniqueBeanDefiniationException 예외를 던진다.

이 때 하위 타입으로 지정할 수 도 있지만 하위 타입으로 지정하는 것은 DIP를 위배하고 무엇보다 그럴꺼면 스프링 왜 쓰니 라고 말할 수 있다.

어떻게 하면 해결할 수 있을까?

Autowired 필드명 매칭

Autowired는 타입 매칭을 시도하고, 만약 여러 빈이 있으면 파라미터 이름으로 빈 이름을 추가한다.

	@Autowired
    public OrderServiceImpl(DiscountPolicy fixDiscountPolicy) {
        this.discountPolicy = discountPolicy;
    }

만약에 이런 코드가 있으면 Autowired는 어떻게 작동할까?

  1. DiscountPolicy 와 매칭되는 타입의 빈을 찾는다.
  2. 하지만DiscountPolicy 타입인 빈이 여러개라면?
  3. 파라미터 변수의 이름인 fixDiscountPolicy 로 등록된 빈을 찾는다 (기본적으로 클래스의 카멜케이스의 이름이 빈으로 등록된다`
    • FixDiscountPolicy -> fixDiscountPolicy 으로 등록되어 있음

@Qualifier 사용

@Quailfier는 추가 구분자를 붙여주는 방법이다. 추가 방법을 제공하는 방법이지 빈 이름을 변경하지는 않는다

사용 방법

@Component
@Qualifer("fixDiscountPolicy")
public class FixDiscountPolicy implements DiscountPolicy {}

@Component
@Qualifer("mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy {}

주입시에 @Quailfier를 붙여주고 등록한 이름을 적어준다

	@Autowired
    public  OrderServiceImpl(@Qualifer("mainDiscountPolicy") DiscountPolicy fixDiscountPolicy) {
        this.discountPolicy = discountPolicy;
    }

생성자를 의존성 주입으로 설정했지만 수정자 자동 주입에서도 동일하게 사용하면 된다.

만약에 @Quailfier를 주입할 떄 @Qualifer("mainDiscountPolicy")의 해당 빈을 못찾으면 어떻게 될까? 그러면 mainDiscountPolicy 라는 이름의 스프링을 찾는다.

하지만 @Quailfier@Quailfier를 찾는 용도로만 사용하자

@Primary 사용

@Primary 는 우선순위를 정하는 방법이다. @Autowired 시에 여러 빈이 매칭되면 @Primary가 우선권을 가진다.

@Component
public class FixDiscountPolicy implements DiscountPolicy {}

@Component
@Priarmy
public class RateDiscountPolicy implements DiscountPolicy {}

이럴 경우 @Prmary를 가진 RateDiscountPolicy가 우선순위를 가진다.

우선 순위

@Primary 는 기본값 처럼 동작하는 것이고 @Quailfier 는 매우 상세하게 동작한다. 스프링은 자동보다는 수동이, 넓은 범위의 선택권 보다는 좁은 범위의 선택권이 우선 순위가 높다. 따라서 @Quailfier가 우선권이 높다.

Collection 으로 주입 받기

만약에 모든 빈들을 주입받고 싶으면 어떻게 할까?

ListMap 같은 컬렉션으로 받을 수 있다.

로그를 찍어보면 정상적으로 두개다 주입 받을는 것을 확인 할 수 있다.

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

어떤 경우에 컴포넌트 스캔과 자동 주입으로 사용을 하고 수동 빈을 사용할까?

애플리케이션은 크게 업무 로직과 기술 로직으로 나눌 수 있다.

  • 업무 로직 : 웹을 지원하는 컨트롤러, 서비스 로직, 데이터 계층을 지원하는 리포지티등이 모두 업무 로직이다.

  • 기술 지원 : 기술적인 공통 관심사를 처리할 떄 주로 사용된다. 데이터베이스 연결, 공통 로그 처리 등 업무 로직을 지원하기 위한 하부 기술 등

결론을 말하자면

업무 로직 을 처리하고 우리가 실제로 비지니스를 구현해야 하는 @Service @Controller @Repositoy 같은 어노테이션이 들어가는 업무 로직은 자동 주입 하자

그 외에 기술 지원에 필요한 객체들은 수동 주입을 통해 설정 정보에 명확하게 나타나게 하는 것이 유지보수 하기 좋다.

하지만 비지니스 로직 중에서 다형성을 적극 활용할 때에는 수동 빈으로 등록하거나 자동으로 하면 특정 패키지에 같이 묶어 두는게 좋다.

정리하자면 @Service @Controller @Repositoy를 사용하는 업무로직은 자동 주입을 하고 스프링 부트가 아니라 내가 직접 기술 지원 객체를 스프링 빈으로 등록한다면 수동으로 등록해서 명확하게 들어내는 것이 좋다 또한 다형성을 적극 활용하는 로직이 있으면 한 패키지에 묶어서 관리하자.

0개의 댓글