본문 바로가기
프로그래밍/세팅 및 오류

[Error] Spring NoSuchBeanDefinitionException 문제

by 노잼인간이라불립니다 2023. 5. 19.

오류 메시지

UnsatisfiedDependencyException: Error creating bean with name ' ' : Un satisfied dependency expressed through field ~~ nestied exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type ~~ available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.bean.factory.annotatins.Autowired(required=true)

오류메시지

0. 개요

 이전에 진행했던 프로젝트의 클라이언트로 부터 새로운 요구사항(새로운 제품코드 추가)이 발생해서, 코드를 수정할 일이 생겼다. (그래서 현재 하드코딩 되어 있는 제품코드를 앞으로 유지보수 용이하게 끔 yml 파일에서 관리할 수 있도록 코드를 변경하였다.)

 

 그런데 모든 코드를 수정하고 나서 테스트를 돌리려고 하니 음? 위와 같은 에러가 발생했다. 오류메시지의 대략적인 내용은 이렇다. 실행 코드에는 x타입의 객체가 있어 Spring container로 부터 x타입을 di시켜서 사용하려고하는데 맞는 타입의 bean이 없다는 것이다.

 

분명히 내 실행 코드에는 문제가 없다고 생각하면서 삽질을 진행했는데, 삽질의 시간은 대략 반나절.. 그리고 중요한 2가지를 깨닫게 된다.

 

1. 문제와 해결

문제 1

 Spring Batch를 실행할 때 하나의 job을 실행하기 위해서는 반드시 Configuration이 필요하다. 그리고 거기서 job에서 사용할 bean들을 정의 해주어야 한다. (필드 주입 방식이던 생성자 주입 방식이던간에..)

 

 그러나 나는 Configuration에서는 bean을 선언하지 않은 bean을, processor단에서 @autowired로 선언해버렸으니.. Spring Container 입장에서는 "응? 처음에 분명 @Configuration에 있는 bean들을 모두 올렸는데... 여기 없는 타입을 DI 해달라고 요청하네??흠.. Exception이나 먹어랏!"  하고 나에게 오류를 던져 주었던 것이다.

 

문제 2

 "음 이번 수정은 간단한 거니까 새로운 필드는 @Autowired로 설정해서 개발속도를 빠르게 올려야 겠다" 라고 생각한 것이 나의 아주 멍청한 처음 생각이었다.(물론 틀린 건 아님. 테스트도 가능은 함..

 

 그러나 위의 오류를 만나게 되면서 영한님에게 배운 세터주입 필드주입 생성자 주입에 대해서 떠올리게 되었고, 결과적으로는 모든 코드를 생성자 주입방식으로 변경하게 되었다.(생성자 주입방식이 좀 더 확장에 유연(어떤 bean을 injection할지 코드 상에서 눈에 보이고, 개발자 입맛대로 변경가능)하고, 가독성이 있다고 판단되었기 때문이다. - 각 주입방식에 대해서는 나중에 시간내서 다시한번 정리 해봐야 겠다!!)

 

 글이 조금 삼천포로 빠진 것 같은데... 결과적으로는 위의 오류는 필드 주입을 사용하였기 때문에 발생한 문제이기도 했다. @autowired하나면 끝나니까. 알아서 넣어주겠지 생각하면서 코딩을 한것이 최종적으로는 큰 패배였다.

 

 즉 정리하자면 나의 첫 번째 잘못은 Spring Batch에서 @Configuration이 어떤 역할을 하는지 무지했다는 것, 두 번째는 생각없이 Bean 주입 방식을 @AutoWired로 정했다는 것이다. (영한님이 강조하신 생성자 주입방식을 사용했어야 했다. ----- 이놈의 귀차니즘...)

 위의 문제점 때문에 결과적으로는 테스트코드를 돌리려고 할 때 맨 위 이미지와 같은 오류가 발생하는 아주 안타까운 현상이 일어났다.

 

해결방법

 무수한 삽질로 반나절이라는 아까운 시간을 보냈지만, 대략적인 나의 해결방법의 프로세스는 아래와 같다.

 

step1. Batch Job Configuration 파일에 로직에서 사용할 Bean을 만들어 선언해준다. 또한 해당 로직에 bean을 매개 변수로 넘겨준다.

step2. 매개변수로 넘겨받은 bean객체를 생성자 주입방식을 이용해 주입 받아 서비스 로직에서 마음껏 사용할 수 있도록 한다.

----------------------------------- 여기 까지가 본 코드에서 오류가 나지 않게 하는 방법-----------------------------------

 

step3. 이번엔 테스트 코드가 제대로 작동할 수 있도록 Injection할 class를 test 코드 맨 위 SpringBootTest의 class속성 값으로 추가해준다. 

step4. @Autowired를 통해 bean을 주입받고, 테스트 시작전에 실행되는 setUp에서 실행할 서비스에서 필요한 bean을 매개변수로 넘겨준다. 

----------------------------------- 여기 까지가 테스트 코드에서 오류가 나지 않게 하는 방법----------------------------------