@Autowired
는 타입으로 조회한다.
ex)
@Component
public class Pizza implements Food {}
@Component
public class Chicken implements Food {}
//자동 주입 실행 시
@Autowired
private Food food;
NoUniqueBeanDefinitionException
오류가 발생
@Autowired
는 타입 매칭을 시도, 여러 빈이 있으면 필드 이름, 파라미터 이름으로 빈 이름을 추가 매칭
// 기존
@Autowired
private Food food
// 필드 명을 빈 이름으로 변경
@Autowired
private Food pizza
필드 명이 pizza
이므로 정상 주입된다.
필드 명 매칭 : 타입 매칭을 시도, 그 결과에 여러 빈이 있을 때 추가로 동작 하는 기능
정리
1. 타입 매칭
2. 타입 매칭의 결과가 2개 이상일 때 필드명, 파라미터 명으로 빈 이름 매칭
@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 라는 이름의 스프링 빈을 추가로 찾는다.
정리
@Qualifier
끼리 매칭
빈 이름 매칭
NoSuchBeanDefinitionException
예외 발생
우선 순위를 정하는 방법
@Autowired
시에 여러 빈이 매칭되면 @Primary
가 우선권을 가짐
ex)
@Primary // 우선권
@Component
public class Pizza implements Food {}
@Component
public class Chicken implements Food {}
@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;
}
해당 타입의 스프링 빈이 다 필요한 경우
Map<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 인터페이스보단 상속 클래스로 쓸걸 그랬다...
🔖 학습내용 출처