인프런 커뮤니티 질문&답변

피엔님의 프로필 이미지
피엔

작성한 질문수

스프링 핵심 원리 - 기본편

조회한 빈이 모두 필요할 때, List, Map

@MainDiscountPolicy 삭제시 오류

작성

·

305

0

안녕하세요 영한님.

복습 도중 에러가 발생하는 부분에 대해 의문이 생겨 질문 남깁니다.

@MainDiscountPolicy 를 RateDiscountPolicy.java와 OrderServiceImpl에서 제거하면 

해당 테스트 수행 시 NoUniqueBeanDefinitionException이 뜹니다.

@Qualifier가 없어도 같은 타입의 빈이면 모두 맵과 리스트에 담기는 것이 이번 강의의 포인트라고 생각되는데..

꼭 @MainDiscountPolicy가 필요하다면 같은 타입의 빈을 조회하는 아이디어가 제대로 작동하지 않는 것 아닌가요?

코드첨부 1. MainDiscountPolicy를 삭제하기 전 - 테스트 모두 통과

package hello.core2.order;

import hello.core2.annotation.MainDiscountPolicy;
import hello.core2.member.Grade;
import hello.core2.member.Member;
import org.springframework.stereotype.Component;

@Component
@MainDiscountPolicy
public class RateDiscountPolicy implements DiscountPolicy {

private int discountPercent = 10;


@Override
public int discount(Member member, int price) {
if (member.getGrade() == Grade.VIP) {
return price * discountPercent / 100;
} else {
return 0;
}
}
}
package hello.core2.order;

import hello.core2.annotation.MainDiscountPolicy;
import hello.core2.member.Member;
import hello.core2.member.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@Component
//@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService{

private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;

// 테스트용도
public MemberRepository getMemberRepository() {
return memberRepository;
}

public OrderServiceImpl(MemberRepository memberRepository, @MainDiscountPolicy DiscountPolicy discountPolicy) {
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);
}
}

코드첨부 2. MainDiscountPolicy를 삭제한 후 - 에러 발생

package hello.core2.order;

import hello.core2.annotation.MainDiscountPolicy;
import hello.core2.member.Grade;
import hello.core2.member.Member;
import org.springframework.stereotype.Component;

@Component
//@MainDiscountPolicy
public class RateDiscountPolicy implements DiscountPolicy {

private int discountPercent = 10;


@Override
public int discount(Member member, int price) {
if (member.getGrade() == Grade.VIP) {
return price * discountPercent / 100;
} else {
return 0;
}
}
}
package hello.core2.order;

import hello.core2.annotation.MainDiscountPolicy;
import hello.core2.member.Member;
import hello.core2.member.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@Component
//@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService{

private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;

// 테스트용도
public MemberRepository getMemberRepository() {
return memberRepository;
}

public OrderServiceImpl(MemberRepository memberRepository, /*@MainDiscountPolicy*/ DiscountPolicy discountPolicy) {
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);
}
}

에러내용

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'orderServiceImpl' defined in file [C:\study\core2\out\production\classes\hello\core2\order\OrderServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'hello.core2.order.DiscountPolicy' available: expected single matching bean but found 2: fixDiscountPolicy,rateDiscountPolicy

at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:799)

at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:228)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1361)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1208)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:556)

at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516)

at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:324)

at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)

at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322)

at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)

at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:897)

at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:879)

at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:551)

at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:89)

at hello.core2.autowired.AllBeanTest.findAllBean(AllBeanTest.java:21)

at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

at java.base/java.lang.reflect.Method.invoke(Method.java:566)

at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:686)

at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)

at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)

at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)

at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)

at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)

at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)

at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)

at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)

at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)

at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)

at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)

at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)

at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)

at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:212)

at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)

at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:208)

at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:137)

at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:71)

at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)

at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)

at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)

at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)

at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)

at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)

at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)

at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)

at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)

at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)

at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)

at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)

at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)

at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)

at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)

at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)

at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)

at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)

at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)

at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)

at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)

at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)

at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)

at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)

at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)

at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)

at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)

at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)

at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)

at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)

at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)

at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)

at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211)

at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)

at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)

at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132)

at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)

at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)

at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)

at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'hello.core2.order.DiscountPolicy' available: expected single matching bean but found 2: fixDiscountPolicy,rateDiscountPolicy

at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:220)

at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1285)

at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1227)

at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:886)

at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:790)

... 77 more

답변 2

0

안녕하세요 영한님! 비슷한 것으로 궁금해서 추가 질문드립니다. 그럼 해당 에러는 AllBeanTest의 컨테이너 생성 과정 중 -> AutoAppConfig.class를 통해 Component Scan을 통한 OrderServiceImpl의 생성과정에 생기는 NoUniqueBeanDefinitionException이라고 이해하면 될까요?

김영한님의 프로필 이미지
김영한
지식공유자

네 맞습니다^^

0

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. 피엔님

현재 오류가 발생하는 부분은 List, Map과 관련된 부분이 아닙니다.

오류 메시지를 보면

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'orderServiceImpl' defined in file [C:\study\core2\out\production\classes\hello\core2\order\OrderServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'hello.core2.order.DiscountPolicy' available: expected single matching bean but found 2: fixDiscountPolicy,rateDiscountPolicy

OrderServiceImpl에 있는 다음 필드에 주입시 오류가 발생합니다.

private final DiscountPolicy discountPolicy;

현재 fixDiscountPolicy,rateDiscountPolicy 두 빈이 등록되어 있습니다.

DiscountPolicy는 둘중 하나를 선택해야 하는데, 선택하는 방법을 지정하지 않았습니다.

감사합니다.

피엔님의 프로필 이미지
피엔

작성한 질문수

질문하기