Spring - 같은 타입의 Bean이 여러개일때 해결방법(NoSuchBeanDefinitionException)

HYK·2022년 5월 13일
0

spring

목록 보기
3/4

설정

개발시에 main DB와 sub DB 가있는데 DB의 종류 가 각각 oracle 과 mysql 이라면

아마 Repository는 2개 여야 할 것이다.

  • OracleMemberRepositoryImpl
@Repository
public class OracleMemberRepositoryImpl implements MemberRepository {

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

    @Override
    public Member findById(Long memberId) {
     	...
    }
}
  • MysqlMemberRepositoryImpl
@Repository
public class MysqlMemberRepositoryImpl implements MemberRepository {

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

    @Override
    public Member findById(Long memberId) {
     	...
    }
}
  • MemberService
@Service
public class MemberServiceImpl implements MemberService {

    private final MemberRepository memberRepository; //interface

	@Autowired
    public MemberServiceImpl(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    @Override
    public void join(Member member) {

    	...

    }

    @Override
    public Member findMember(Long memberId) {

       ...

    }

}


테스트

이상태로 Spring을 실행시키면 어떻게될까??


@SpringBootTest
class CoreApplicationTests {

	@Test
	void contextLoads() {
	}

}

오류발생

다음과 같은 오류가 발생한다
Spring org.springframework.beans.factory.NoSuchBeanDefinitionException ~~~ expected single matching bean but found 2

무슨뜻일까? 번역해보니 일치하는 빈을 2개 찾았다는 뜻이다. 즉 같은 타입의 빈이 정의 되있을경우 그냥 Autowired로 주입시에는 오류가 발생한다.


해결방법

방법 1. Autowired의 속성을 이용한다.

방금 Autowired로만 안된다고 했는데 한가지 방법이 있다.
바로 필드 이름이나 파라미터를 구체적인 클래스로 변경하는것이다.

  • MemberService
@Service
public class MemberServiceImpl implements MemberService {
	/**
	* 필드를 변경하거나 파라미터를 변경하거나 둘중에 하나만 구체적인 클래스명으로 변경하면됌.
    **/
    private final MemberRepository oracleMemberRepositoryImpl; 

	@Autowired
    public MemberServiceImpl(MemberRepository oracleMemberRepositoryImpl) {
        this.memberRepository = memberRepository;
    }

  .
  .
  .
}

방법 2. @Qualifier 어노테이션 이용하기

아래와 같이 각 Repository에 Qualifier를 이용해 별칭을 지어준다.

  • OracleMemberRepositoryImpl(main)
@Repository
@Qualifier("main")
public class OracleMemberRepositoryImpl implements MemberRepository {

   .
   .
   .

}
  • MysqlMemberRepositoryImpl(sub)
@Repository
@Qualifier("sub")
public class MysqlMemberRepositoryImpl implements MemberRepository {

   .
   .
   .

}
  • MemberService
    MemberService에서 주입받고자하는 Repositroy를 Qualifier를 이용해서 받으면된다.
@Service
public class MemberServiceImpl implements MemberService {

    private final MemberRepository memberRepository; //interface

	@Autowired
    //사용하고자 하는 Repository의 별칭 지정
    public MemberServiceImpl(@Qualifier("main")MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

   .
   .
   .

}

방법 3. @Primary어노테이션 이용하기

다음과 같이 두개의 Repository 중 사용한 Repository에 @Primary를 붙여놓으면 기본으로 해당클래스가 주입이 된다.(즉 충돌하지않고 Primary가 붙은 빈이 주입됌)

  • OracleMemberRepositoryImpl
@Repository
@Primary //기본값
public class OracleMemberRepositoryImpl implements MemberRepository {

   .
   .
   .

}

# 우선순위

@Qualifier 와 @Primary 가 둘다 있을경우 Qualifier를 우선으로 적용한다.

출처 : 스프링 핵심 원리

profile
Test로 학습 하기

0개의 댓글