강의

멘토링

커뮤니티

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

drj9812님의 프로필 이미지
drj9812

작성한 질문수

스프링 핵심 원리 - 기본편

"중복 등록과 충돌" 강의에서 강사님과 다른 에러가 발생합니다.

작성

·

13

·

수정됨

0

spring.main.allow-bean-definition-overriding=true

07:05~ 부분에서 위 코드를 작성하면 스프링 부트 애플리케이션을 에러가 발생하지 않는 모습을 보여주셨는데요.

20:53:29.311 [main] DEBUG o.s.b.d.LoggingFailureAnalysisReporter --Application failed to start due to an exception
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'drj9812.spring.member.MemberRepository' available: expected single matching bean but found 2: memoryMemberRepository,memberRepository
	at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:192)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1739)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1651)
	at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:912)
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791)
	at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:240)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1382)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1221)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:565)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:525)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:333)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:371)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:331)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:196)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.instantiateSingleton(DefaultListableBeanFactory.java:1218)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingleton(DefaultListableBeanFactory.java:1184)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:1121)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:983)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:620)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:765)
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:454)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:321)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1374)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363)
	at drj9812.spring.Application.main(Application.java:10)
20:53:29.311 [main] ERROR o.s.b.d.LoggingFailureAnalysisReporter --

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of constructor in drj9812.spring.member.MemberServiceImpl required a single bean, but 2 were found:
	- memoryMemberRepository: defined by method 'memberRepository' in class path resource [drj9812/spring/AutoAppConfig.class]
	- memberRepository: defined by method 'memberRepository' in class path resource [drj9812/spring/AppConfig.class]

This may be due to missing parameter name information

Action:

Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed

Ensure that your compiler is configured to use the '-parameters' flag.
You may need to update both your build tool settings as well as your IDE.
(See https://github.com/spring-projects/spring-framework/wiki/Spring-Framework-6.1-Release-Notes#parameter-name-retention)

저의 경우엔 위와 같은 에러가 발생합니다.

  1. 강사님과 다르게 저는 에러가 발생한 이유가 무엇인가요?

  2. 로그 내용을 보아 AutoAppConfigAppConfig이 충돌이 난 것 같은데, 이미 AutoAppConfig에서 excludeFiltersAppConfig은 스캔하지 않도록 설정했으니 에러가 발생하지 않아야 되는 거 아닌가요?

     

답변 2

0

안녕하세요, 인프런 AI 인턴입니다. drj9812님께서 스프링 빈 충돌 문제에 대해 질문을 주셨습니다. 현재 주신 로그에는 NoUniqueBeanDefinitionException 에러가 나타나고 있습니다. 이는 스프링 컨테이너에서 동일한 타입의 빈이 두 개 이상 등록된 경우 발생하는 에러입니다.

문제의 원인

  1. 빈 중복 등록: AutoAppConfigAppConfig 둘 다 MemberRepository 타입 빈을 등록하고 있어서 발생하는 문제인 것 같습니다.
  2. excludeFilters 오작동: excludeFilters가 설정되었더라도, AppConfig의 빈 등록 메서드가 접근 가능한 경로에 있을 경우 자동 실행될 수 있습니다. 스프링이 어떤 방식으로 코드를 해석하거나, 프로젝트 셋업에 따라 다르게 동작할 수 있습니다.

해결 방안

  1. 빈 우선순위 설정: 두 빈 중 하나를 기본으로 사용하게 하려면 @Primary 어노테이션을 사용하여 기본 빈을 지정하여 충돌을 해결할 수 있습니다.
   @Bean
   @Primary
   public MemberRepository memberRepository() {
       return new MemoryMemberRepository();
   }
  1. @Qualifier 사용: 특정 빈을 주입받기 위해 @Qualifier를 사용하여 명확하게 어떤 빈을 주입받을 것인지 지정할 수 있습니다.
   @Autowired
   public MemberServiceImpl(@Qualifier("memoryMemberRepository") MemberRepository memberRepository) {
       this.memberRepository = memberRepository;
   }
  1. Configuration 클래스 정리: AppConfig 또는 AutoAppConfig 중 하나에서만 해당 빈을 등록하도록 구조를 정리할 수 있습니다. 서로 다른 부트스트랩 사이클로 인해 특정 빈이 예상치 못하게 등록되는 것을 방지할 수 있습니다.

  2. 빈 이름 변경: 빈 이름을 다르게 설정하여 중복을 피할 수 있습니다.

아래의 링크는 스프링 빈 중복 등록과 관련된 문제 해결 방법을 설명하는 유사한 질문들입니다:
- 스프링 빈 중복 등록 해결 방법
- 빈 등록 시 주의할 점

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

0

drj9812님의 프로필 이미지
drj9812
질문자

@Configuration
public class AppConfig {
	
	@Bean
	public MemberService memberService() {
		return new MemberServiceImpl(memberRepository());
	}

	@Bean
	public MemberRepository memberRepository() {
		return new MemoryMemberRepository();
	}
	
	@Bean
	public OrderService orderService() {
		return new OrderServiceImpl(memberRepository(), discountPolicy());
	}

	@Bean
	public DiscountPolicy discountPolicy() {
		return new RateDiscountPolicy();
	}
}

@Configuration
@ComponentScan(
		basePackages = "drj9812.spring.member",
		excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class)
)
public class AutoAppConfig {
	
	@Bean(name = "memoryMemberRepository")
	MemberRepository memberRepository() {
		return new MemoryMemberRepository();
	}
}

@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 selectByMemberId(Long memberId) {
		return store.get(memberId);
	}
}

@SpringBootApplication
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}
}

제 코드입니다.

drj9812님의 프로필 이미지
drj9812

작성한 질문수

질문하기