상황
- FCM 기능을 추가하기 위해서 해당 클래스와 메서드를 구현하던 중, 필요한 변수를 설정 중
- 해당 변수들을 코드 단에 application.yml에서 @Value 어노테이션을 이용해서 주입해주려 했으나 서버를 실행시키면 에러가 발생
에러
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in ~ required a bean of type 'java.lang.String' that could not be found.
Action:
Consider defining a bean of type 'java.lang.String' in your configuration.
Process finished with exit code 0
설명을 직역하자면, "해당 클래스에 있는 생성자의 매개 변수는 "java.lang.String" 타입의 빈이 필요한데, 찾을 수 없다 "이다.
즉, 생성자에서 String type Bean이 필요한데 없다!
@Component
@RequiredArgsConstructor
public class FirebaseCloudMessageService {
@Value("${firebase.key}")
private final String firebaseConfigPath;
@Value("${firebase.apiUrl}")
private final String API_URL;
private final ObjectMapper objectMapper;
나의 코드는 다음과 같았다. lombok의 RequiredArgsConstructor를 통해서 의존성 주입을 하려 했었다.
final 키워드, 혹은 NotNull인 필드 값만 파라미터로 받는 생성자가 만들어져서 의존성 주입이 되는데, 위의 코드를 보면 String 변수에 모두 final이 붙어있다.
firebaseConfigPath와 API_URL은 String 타입의 변수일뿐, 스프링 컨테이너에 등록되어 관리하는 Bean이 아니므로
의존성을 주입할 수 없다는 것이었고
저 코드대로 동작을 하는 경우 RequiredArgsConstructor가 생성자를 만들어서 의존성을 주입해주는 타이밍에서 String 타입의 빈을 요구한 것이었다.
하지만 없으니 "Consider defining a bean of type 'java.lang.String' in your configuration"의 Action이 추천된 것..
(String type의 bean을 정의하는 것을 고려해봐라!)
+ 그럼 objectMapper는?
objectMapper와 같은 외부 라이브러리들은 Bean으로 등록돼서 관리가 되므로, 문제없이 주입이 되는 것이었다.
추가로 @Value를 통해 값이 매핑되는 시점은 스프링 컨테이너에서 Bean을 등록할 때, @Value가 있으면 application.yml에서 값을 찾아서 넣어준다고 한다.
실제 런타임 시
@Component
public class SampleA {
} // Component를 통해 Bean 등록
public class TestA {
private SampleA sampleA;
@Autowired
public testA(SampleA sampleA) {
this.sampleA = sampleA; // Bean으로 관리되는 SampleA를 @Autowired를 통한 생성자 주입
}
}
이와 같이 생성자가 만들어질 텐데, private final String xxx는 String type은 관리되는 빈이 아니므로 주입이 불가능하다.
결론
이 에러는 의존성 주입 시 주입되는 특정 클래스가 Bean으로 관리가 되지 않아서 발생하는 문제였으며
String 뿐만 아니라 특정 클래스의 에러가 나는 경우 해당 클래스가 Bean으로 등록되었는지 확인해볼 필요가 있다.
~~~ required a bean of type '특정 클래스' that could not be found.
해당 클래스를 가서 확인해보자.
@Service, @Repository, @Controller, @Component 등 어노테이션이 빠져서
스프링 컨테이너에 Bean 등록이 되지 않은 상태일 수 있다.