안녕하세용 오늘은... 간단한건데
제가 깃허브 리드미에 트러블슈팅 메모를 남겨놨길래 티스토리에 옮겨 적는
스프링 빈으로 등록하려고 했을 때 발생할 수 있는 Could not autowire 에러에 대해서 뜯어보겠습니다
사실 이건 의존관계를 잘 생각해서 구현하면... 잘 볼 수 없다고 생각하지만 (물론 저의 생각)
인생이란? 야속하게도 멀쩡하게 굴러가지 않을 때가 훨씬 더 많기도 하고
제가 의존관계부터 공부를 다시 시작했을 때 시뻘건 줄 박박 그어진거보고 개큰울음을 발싸했기때문에...
저처럼 스프링 공부하시는분들은 심심치않게보지않을까? 싶습니다
물론 이것도 그냥 저의 생각입니따 우땨땨...
잡담 그만하고 바로 드가겠습니다 레쭈고
1. 에러 내용 확인

Could not autowire. There is more than one bean of 'MemberRepository' type.
Beans: memoryMemberRepository (MemoryMemberRepository.java)
springDataJpaMemberRepository (SpringDataJpaMemberRepository.java)
에러 해석)
memoryMemberRepository 와 springDataJpaRepository 가 둘 다 스프링 빈으로 등록되어있다... 하나만 등록할 수 있다!
2. 에러 해결 과정
저는 스프링 빈을 수동 등록하고, 관리하는 DI 컨테이너 역할을 하는 SpringConfig.java 라는 파일을 따로 만들어놔서 거기서 코드를 다시 봤는데, MemoryMemberRepository 에서 스프링 빈으로 주입한 건 다 주석으로 막았는데 왜 등록되었나 긴가민가한 상태였습니다
(근데 보통 이러면 제가 공부하다가 잠깐 졸았거나 정신 안 차리고 공부했거나 이렇긴 합니다)
근데 역시 제가 하나 놓치고 있던 것이 있었으니...
바로 MemoryMemberRepository.java 에 제가 스프링 빈을 주입하려고 기입해둔 @Repository 어노테이션이었습니다
- MemoryMemberRepository.java 코드는 H2 DB 연결하기 전에 사용하던 메모리 저장용 코드라서 스프링 빈으로 등록된 상태를 고쳐줘야했습니다 (springDataJpaRepository 가 스프링 빈으로 정상적으로 주입될 수 있도록)
- 근데 SpringConfig에 MemoryMemberRepository 사용과 관련된 Bean은 다 주석으로 막아놨는데 왜 등록되어있나 봤더니 @Repository 어노테이션을 사용하면 SpringConfig에 Bean으로 수동 등록하지 않아도 스프링이 자동으로 스프링 빈으로 등록해버려서, 스프링 입장에서는 먼저 등록된 MemoryMemberRepository 말고는 등록을 받을 수가 없었따... 🥹
- 그래서 MemoryMemberRepository 에 붙어있는 @Repository 어노테이션까지 제거해야 스프링 빈을 다른걸로 등록할 수 있었습니다...
그래서 놀랍게도 MemoryMemberRepository.java 가서 @Repository 어노테이션을 제거해주니! SpringConfig에서 스프링 빈으로 memoryMemberRepository 를 스프링 빈으로 수동 등록할 수 있었다는 이야기! (간단하다)
(추가로, 이건 인텔리제이의 짜잘한 버그같은데, MemoryMemberRepository.java 코드를 수정해줬는데도 여전히 SpringConfig 코드의 Autowire 관련 에러가 표시되길래 뭐지? 하고 그냥 테스트 코드를 돌려봤는데 딱히 에러 없이 잘 실행되더라는 이야기... 인텔리제이를 종료했다가 키니까 SpringConfig 코드에 에러는 사라졌습니다 ㅎ... 어쨌던 햅삐엔딩! 햅삐햅삐햅삐ㅣ)
3. @Bean (스프링 빈 수동 등록) 와 @Repository (스프링 빈 자동 등록)
저처럼 DI 컨테이너를 따로 만들어서 스프링 빈을 수동 등록해도 되지만, 보~통은 이제 @Component 어노테이션을 쓰거나, @Component 하위 어노테이션인 @Configuration, @Controller, @Service, @Repository 를 쓰는 경우가 많습니다
그래서 스프링 빈을 수동 등록하는 상황과 자동 등록을 하는 상황을 나눠서 정리하고 글을 마치겠습니다
3-1. 스프링 컨테이너에 빈을 수동 등록하는 경우 (@Bean, @Configuration 사용)
- 개발자가 직접 제어가 불가능한 라이브러리를 빈으로 등록할 때 불가피하게 사용하는 경우, 스프링 컨테이너에 빈을 수동 등록하는 방법을 쓴다.
- 또는, 유지보수성을 높이기 위해 애플리케이션 전범위적으로 사용하는 객체 (ex. 기술 지원), 다형성을 활용하여 여러 구현체를 빈으로 등록할 때 사용한다. 이런 경우에는 수동 등록 방법을 사용하면, DI 컨테이너에서 코드만 보고도 어떤식으로 빈이 등록되었는지, 의존관계가 주입되었는지 확인이 가능하기 때문이다.
- @Bean 만 사용해도 스프링이 빈으로 등록해주지만, 싱글톤을 보장해주지 않기 때문에, 스프링 설정 정보는 항상 @Configuration 어노테이션을 사용하는 것이 보편적이다.
3-2. 스프링 컨테이너에 빈을 자동 등록하는 경우 (@Component)
- 스프링의 컴포넌트 스캔 기능을 활용하여 xml이나 @Bean 을 사용해서 스프링 빈을 수동으로 직접 등록하는거 말고, 설정 정보 없이도 자동으로 스프링 빈으로 등록하는 기능을 활용 (컴포넌트 스캔은 @Autowired 어노테이션을 통해 의존관계를 자동으로 주입하는 기능도 제공함)
- 스프링의 컴포넌트 스캔 기능은 @Component 어노테이션이 있는 클래스를 자동으로 찾아서 빈으로 등록해준다 (하위 어노테이션으로는 @Configuration, @Controller, @Service, @Repository 가 있다.)
- 스프링 컴포넌트 스캔 기능을 활용해서 스프링 컨테이너에 빈을 자동으로 등록하면, 빈의 이름도 자동으로 설정해주는데, 파일명에서 앞글자만 소문자로 바꿔주고 알아서 낙타표기법 써서 등록해준다. (그래서 앵간해서는 빈 이름에서 충돌나는 경우는 없다)
- 3-1 에서 언급한 특이케이스가 아니라면 이 방식으로 스프링 컨테이너에 빈을 등록하는 방법을 사용한다.
- 스프링은 수동 등록한 빈과 자동 등록한 빈이 충돌하는 경우, 수동 등록된 빈이 우선권을 가진다. (수동 빈이 자동 빈을 오버라이딩함, 원래 로그 한 줄 남고 따로 터지는 에러 없이 실행되지만, 이런게 꼬여서 나중에 애~매한 버그로 스노우볼되서 난리나는 경우가 있다... 그래서 최근 스프링부트에서는 수동 등록된 빈과 자동 등록된 빈이 충돌되면 정상 실행되지 않고 에러가 발생하도록 기본 값을 바꾸었다.)
끝! 뭔가 급 마무리같지만
읽어주셔서 감사합니따 😘
🍀
좋아하는 것을 계속 좋아하세요!
반드시 행복해집니다
백엔드 개발자가 되고 싶어서 열심히 헤딩 중인 재영입니다 :-)
[Github] https://github.com/chujaeyeong
[E-mail] chujy1224@gmail.com
'Study > Spring' 카테고리의 다른 글
| MySQL에서 제공하는 Lock을 이용해서 동시성 제어하기 (Pessimistic Lock, Optimistic Lock, Named Lock) (0) | 2024.08.17 |
|---|---|
| 선착순 쿠폰 발급 시스템 로직 변경으로 Redis의 Set 자료구조 찍먹해보기 (0) | 2024.07.02 |
| 선착순 쿠폰 발급 시스템 개발을 통해 Redis 랑 Kafka 찍먹해보기 (2) | 2024.07.01 |
| [Spring] Validation (검증) 처리 방법 및 properties 파일의 한글이 출력되지 않는 문제 해결 방법 (2) | 2023.10.12 |
| [Spring] BeanNotOfRequiredTypeException (스프링 빈 등록 에러) 발생 시 체크사항 정리 (0) | 2023.09.16 |