작성
·
247
0
@Configuration
public class AppConfig {
@Bean
public MemoryMemberRepository memoryRepository() {
return new MemoryMemberRepository();
}
@Bean
public RateDiscountPolicy discountPolicy() {
return new RateDiscountPolicy();
}
@Bean
public MemberService memberService(){
return new MemberServiceImpl(memoryRepository());
}
@Bean
public OrderService orderService(){
// return null;
return new OrderServiceImpl(memoryRepository(), discountPolicy());
}
}
저는 지금까지 위의 코드처럼 MemoryMemberRepository
빈 객체를 생성하는 메서드의 이름을 memberRepository
가 아니라 memoryRepository
로 이름지어주고 진행해왔습니다.
그러다가 7.의존관계 자동 주입 챕터에서 test 폴더를 전부 테스트할 때
CoreApplicationTests에서 동일한 타입에 여러 Bean이 생성되었다는 오류 메시지를 받았습니다.
Parameter 0 of constructor in hello.core.member.MemberServiceImpl required a single bean, but 2 were found:
- memoryMemberRepository: defined in file [C:\Users\***\***\coding\source_code\Spring\inflearn2\out\production\classes\hello\core\member\MemoryMemberRepository.class]
- memoryRepository: defined by method 'memoryRepository' in class path resource [hello/core/AppConfig.class]
///
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'hello.core.member.MemberRepository' available: expected single matching bean but found 2: memoryMemberRepository,memoryRepository
해결하려는 과정에서 강의노트에 메서드 이름이 memberRepository
였다는걸 알게됐고 이걸로 이름을 고쳐주고 다시 테스트하니까 정상적으로 테스트가 완료됐습니다.
메서드 이름만 바꿔준 것만으로 NoUniqueBean 오류가 해결된 이유가 궁금해졌습니다.
이것저것 코드를 건드렸는데 @Component
코드들을 아래에 붙이겠습니다. 감사합니다.
@Component
public class MemberServiceImpl implements MemberService{
private MemberRepository store;
@Autowired
public MemberServiceImpl(MemberRepository memberRepository){
this.store = memberRepository;
}
@Override
public void register(Member newMember) {
store.save(newMember);
}
@Override
public Member search(Long memberId) {
return store.findById(memberId);
}
}
@Component
public class MemoryMemberRepository implements MemberRepository{
private static Map<Long, Member> store = new HashMap<>();
@Override
public void save(Member member) {
store.put(member.getId(), member);
}
@Override
public Member findById(Long memberId) {
return store.get(memberId);
}
}
@Component
public class OrderServiceImpl implements OrderService {
private MemberRepository memberRepository;
private DiscountPolicy discountPolicy;
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
System.out.println("Constructor DI");
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
@Override
public Order createOrder(Long memberId, String itemName, int itemPrice) {
Member member = memberRepository.findById(memberId);
int discountPrice = discountPolicy.discount(member, itemPrice);
return new Order(memberId, itemName, itemPrice, discountPrice);
}
}
@Component
public class RateDiscountPolicy implements DiscountPolicy{
private static final double DISCOUNT_RATE = 0.1;
@Override
public int discount(Member member, int price) {
if(member.getGrade() == Grade.VIP)
return (int) (price * DISCOUNT_RATE);
else
return 0;
}
}
답변 1
0
안녕하세요, 인프런 AI 인턴이에요.
@Bean으로 등록된 메서드는 해당 메서드의 이름을 빈의 이름으로 사용합니다. 따라서, 메서드의 이름을 아무렇게나 지으면 안되고, 해당 빈을 가져다 쓸 때 메서드 이름으로 호출해야 합니다.
예를 들어, 위의 코드에서 memoryRepository() 메서드는 MemoryMemberRepository 타입의 빈을 생성하는 메서드입니다. 그래서 memberService()와 orderService() 메서드에서 이 빈을 사용하기 위해서는 메서드 이름으로 호출해야 합니다.
만약, 메서드의 이름을 memoryRepository 대신 다른 이름으로 지정한다면, 해당 이름으로 호출하면 메서드를 찾을 수 없기 때문에 NoSuchBeanDefinitionException 오류가 발생할 수 있습니다.
또한, 같은 타입의 빈이 여러 개 존재하는 경우에는 @Qualifier 애노테이션을 사용하여 어떤 빈을 주입할지 명시해야 합니다.
따라서, 수정 전 코드 상태에서는 bean의 이름을 memoryRepository로 바꿔줘야 합니다.