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

wonjchoi님의 프로필 이미지
wonjchoi

작성한 질문수

스프링 핵심 원리 - 기본편

옵션 처리

NoUniqueBeanDefinitionException 에러 질문입니다.

작성

·

578

0

 

 

***************************

APPLICATION FAILED TO START

***************************

 

Description:

 

Parameter 0 of constructor in hello.core.member.MemberServiceImpl required a single bean, but 2 were found:

- memoryMemberRepository: defined in file [/Users/choewonjun/IdeaProjects/core/out/production/classes/hello/core/member/MemoryMemberRepository.class]

- memberRepository: defined by method 'memberRepository' in class path resource [hello/core/AppConfig.class]

 

 

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

 

위와 같이 에러가 발생합니다. 아마도 싱글톤이 하나가 아니라 두개가 정의되어있다는것 같은데 아무리 찾아도 왜 두개가 등록 되어 있는지 모르겠어요 ㅠㅠ

 

 

 

 

 

MemberServiceImpl

package hello.core.member;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MemberServiceImpl implements MemberService{

//	private final MemberReposiroty memberReposiroty = new MemoryMemberRepository(); 이것은 마치 배우가 직접 담당 배역을 설정
	private final MemberReposiroty memberReposiroty;

	@Autowired
	public MemberServiceImpl(MemberReposiroty memberReposiroty) {
		System.out.println("memberReposiroty = " + memberReposiroty);
		System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
		this.memberReposiroty = memberReposiroty;
	}

	@Override
	public void join(Member member) {
		memberReposiroty.save(member);
	}

	@Override
	public Member findMember(Long memberId) {
		return memberReposiroty.findbyID(memberId);
	}

	// 테스트 용도
	public MemberReposiroty getMemberReposiroty(){
		return memberReposiroty;
	}
}

 

MemoryMemberRespository

package hello.core.member;


import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;


@Component
public class MemoryMemberRepository implements MemberReposiroty {

	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);
	}
}

 

 

AutoAppConfig

package hello.core;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;

@Configuration
@ComponentScan( // 스캔해서 빈에 자동 등록
//		basePackages = "hello.core.member",
		excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class)
)

public class AutoAppConfig {

}

 

AppConfig

package hello.core;

import hello.core.discount.DiscountPolicy;
import hello.core.discount.FIxDiscountPolicy;
import hello.core.discount.RateDiscountPolicy;
import hello.core.member.*;
import hello.core.order.OrderService;
import hello.core.order.OrderServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

	@Bean
	public MemberService memberService(){
		System.out.println("call AppConfig.memberService");
		return new MemberServiceImpl(memberRepository());
	}

	@Bean
	public MemberReposiroty memberRepository() {
		System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
		System.out.println("call AppConfig.memberRepository");
		return new MemoryMemberRepository();
	}

	@Bean
	public OrderService orderService(){
		System.out.println("call AppConfig.orderService");
		return new OrderServiceImpl(memberRepository() , discountPolicy());
	}

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

답변 1

2

안녕하세요. wonjchoi님, 공식 서포터즈 David입니다.

MemoryMemberRepository 클래스에 @Repository가 붙으면 빈으로 등록합니다.

@Configuration이 붙은 AppConfig 내 @Bean이 붙은 memberRepository()에서 MemoryMemberRepository를 반환하고 있습니다. 설정 정보 클래스에서 해당 메서드와 같이 선언하면 반환 객체를 빈으로 등록합니다.

따라서, 2개의 빈이 존재하게 되므로 오류가 발생합니다.

감사합니다.

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

안녕하세요! 답변 정말 감사합니다 그런데 아직 의문이 해결되지 않아서요 ㅠㅠ

MemoryMemberRepository 클래스에 @Repository가 붙으면 빈으로 등록된다고 하셨는데 위에 MemoryMemberRepository 클래스를 보면  @Repository 가 붙어 있지 않은데 왜 빈이 등록되는지 궁금합니다.

또한 AutoAppConfig 클래스에서 @ComponentScan 에 excludeFilters 를 지정해줘서 AppConfig 클래스에 있는 @Configuration 는 스캔 대상에서 제외되는것 아닌가요? 그런데 왜 AppConfig 내 @Bean이 붙은 memberRepository()에서 MemoryMemberRepository를 반환하는지 궁금합니다.

1. @Component가 붙어 있어서 빈으로 등록됩니다.

2. 패키지 목록까지 올려주신게 아니라서 로그보고 말씀드렸습니다.

아래 로그 보시면 AppConfig에서 MemoryMemberRepository를 반환한다고 되어있습니다.

베이스 패키지가 잘못 세팅되었던가, 패키지 경로가 잘못되었을 가능성이 있습니다. 확인해주세요.

wonjchoi님의 프로필 이미지
wonjchoi

작성한 질문수

질문하기