스프링 - 의존관계 자동 주입 2

meluu_·2023년 8월 12일
0

스프링

목록 보기
6/27
post-thumbnail

🌿 조회 빈 중복 문제


@Autowired 는 타입으로 조회한다.

ex)

@Component
public class Pizza implements Food {}

@Component
public class Chicken implements Food {}
//자동 주입 실행 시 
@Autowired
private Food food;

NoUniqueBeanDefinitionException 오류가 발생

  • 하위 타입으로 지정 가능 하지만 DIP를 위배하고 유연성이 떨어진다.
  • 이름만 다르고, 완전히 똑같은 타입의 스프링 빈이 2개 있을 때 해결 X

@Autowired 필드명, @Qualifier, @Primary


@Autowired 필드 명 매칭

@Autowired는 타입 매칭을 시도, 여러 빈이 있으면 필드 이름, 파라미터 이름으로 빈 이름을 추가 매칭

// 기존
@Autowired
private Food food

// 필드 명을 빈 이름으로 변경
@Autowired
private Food pizza

필드 명이 pizza 이므로 정상 주입된다.
필드 명 매칭 : 타입 매칭을 시도, 그 결과에 여러 빈이 있을 때 추가로 동작 하는 기능

정리
1. 타입 매칭
2. 타입 매칭의 결과가 2개 이상일 때 필드명, 파라미터 명으로 빈 이름 매칭


@Qualifier 사용


@Qualifier는 추가 구분자를 붙여주는 방법 (빈 이름 변경 X)

@Component
@Qualifier("mainFood")
public class Pizza implements Food {}

@Component
@Qualifier("chicken")
public class Chicken implements Food {}

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

생성자 자동 주입 예시

@Autowired
public MenuImpl(@Qualifier("mainFood") Food food) {
	this.food = food;
}

수정자 자동 주입 예시

@Autowired
public setFood(@Qualifier("mainFood") Food food) {
	this.food = food;
}

수동 빈 등록시에도 동일하게 사용 가능

@Bean
@Qualifier("mainFood")
public Food food() {
 return new ...
}

@Qualifier("mainFood)를 못찾으면 mainFood 라는 이름의 스프링 빈을 추가로 찾는다.

정리

  1. @Qualifier끼리 매칭

  2. 빈 이름 매칭

  3. NoSuchBeanDefinitionException 예외 발생


Primary 사용


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

ex)

@Primary        // 우선권
@Component
public class Pizza implements Food {}

@Component
public class Chicken implements Food {}
  • 따로 해줄 것은 없다. 조회시 Primary가 먼저 우선권을 가져서 주입된다.

Primary vs Qualifier 우선순위

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

즉, Qualifier이 우선권이 높다

애노테이션 직접 만들기

@Qualifier("mainFood") 이렇게 문자를 적으면 컴파일시 타입 체크 불가
다음과 같은 애노테이션을 만들어서 문제를 해결 가능

package hello.core.annotataion;
import org.springframework.beans.factory.annotation.Qualifier;
import java.lang.annotation.*;


@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER,
ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Qualifier("mainFood")
public @interface MainFood {
}

Target, Retention,Documented는 자세히 모르지만 추후에 배워볼 예정


//생성자 자동 주입
@Autowired
public MenuImpl(Food food) {
	this.food = food;
}

//수정자 자동 주입
@Autowired
public Food setFood(@MainFood Food food) {
	this.food = food;
}

조회 빈이 모두 필요할 때


List, Map

해당 타입의 스프링 빈이 다 필요한 경우

Map<String, 타입>

  • String : 빈 이름(스프링 컨테이너)

List<타입>

@Component
public class FindAllBean {

	private final Map<String, Food> foodMap;
    private final List<Food> foodList;
    
    @Autowired
    public void findAllBean(Map<String, Food> foodMap, List<Food> foodList)) {
    	this.foodMap = foodMap;
    	this.foodList = foodList;
	}
    
    public void findBean(String bean) {
    	Food food = foodMap.get(bean);
        System.out.println("food.getClass() = " + food.getClass());
    
    }
}
@Test
void run() {
	AnnotationConfigApplicationContext ac = 
    					new AnnotationConfigApplicationContext(AppConfig.class);
    FindAllBean bean = ac.getBean(FindAllBean.class);

    bean.findBean("pizza");
    bean.findBean("chicken");
    


}


자동,수동의 올바른 실무 운영 기준은 강의와 강의자료를 참고하자
Food 인터페이스보단 상속 클래스로 쓸걸 그랬다...


🔖 학습내용 출처

스프링 핵심 원리 - 기본편

profile
열심히 살자

0개의 댓글