Spring Framework

Spring Bean 이름은 왜 소문자로 시작할까?

Junuuu 2024. 11. 3. 17:06
728x90

개요

특정상황에서 Spring Bean의 이름으로 컨테이너에서 가져와서 활용하는 경우가 있었고 그 경우에 NoSuchBeanException이 발생하여 문제의 원인을 파악하고 알게 된 내용들을 정리해보고자 합니다.

 

스프링 컨테이너에 등록된 빈 이름은 어떻게 될까요?

@Component
class Z

@Component
class FooBar

@Component
class HTMLParser

 

대부분 일반적으로 앞자리가 소문자로 바뀌게 된다고 알고 있습니다.

Z는 z로 FooBar는 fooBar로 HTMLParser는 hTMLParser로 바뀌게 될까요?

 

@Component
class BeanTest(
	private val applicationContext: ApplicationContext
): ApplicationRunner{
	override fun run(args: ApplicationArguments?) {
		applicationContext.getBean("z")
		applicationContext.getBean("fooBar")
		applicationContext.getBean("hTMLParser")
	}
}

 

위 코드를 실행해보면 아래와 같이 hTMLParser라는 이름의 빈을 찾을 수 없다는 에러 문구가 나옵니다.

 

Description:

A component required a bean named 'hTMLParser' that could not be found.


Action:

Consider defining a bean named 'hTMLParser' in your configuration.

 

디버깅을 해보자

 

디버깅을 해보면 hTMLParser가 아닌 HTMLParser로 빈 이름이 등록된 것을 확인해 볼 수 있습니다.

그렇다면 빈 이름은 어떤 규칙에 의해 정해지는걸까요?

그리고 왜 그런 규칙이 생기게 되었을까요?

 

스프링이 빈 이름을 정하는 방법

 

beanName이 지정되어 있지 않는다면 AnnotationBeanNameGenerator의 generateBeanName이 호출됩니다.

 

 

AnnotationBeanNameGenerator의 buildDefaultBeanName 메서드가 StringUtils.uncapitalizeAsProperty() 메서드를 호출하여 ClassName의 uncapitalize(소문자화)를 수행합니다.

 

소문자화의 규칙은 무엇일까?

 

isUpperCase()를 통하여 클래스의 이름 중 첫 번째 문자와, 두번째 문자가 대문자라면 그대로 반환합니다.

즉 HTML과 같이 대문자가 연속으로 등장하는 경우 소문자화가 이루어지지 않습니다.

 

그 외의 케이스는 첫번째 문자를 소문자화시킵니다.

 

위 규칙에 따르면 Z는 z로 FooBar는 fooBar로 HTMLParser는 HTMLParser로 바뀌게 됩니다.

 

왜 이런 규칙을 가지게 될까?

https://download.oracle.com/otn-pub/jcp/7224-javabeans-1.01-fr-spec-oth-JSpec/beans.101.pdf?AuthParam=1730612779_1eabd53971cde79e32822516e6503560

Oracle의 JavaBeans Spec의 문서를 보게 되면 8.8 section에 Capitalization of inferred names을 찾을 수 있습니다.

 

대문자인 경우는 약어로 판단하고 소문자화 시키는 것이 더 이해하기 어렵고 의미를 해친다고 생각하여 대문자가 2자 이상 연속되는 경우에는 그대로 반환하게 됩니다.

 

위 컨벤션에 따라서 Introspector 클래스의 decapitalize 메서드에 로직이 구현되어 있습니다.

 

결론

자바빈 규약에 대해 모르는 부분들이 있었으며 단순히 앞글자가 소문자로만 바뀐다고 오해하고 있었습니다.

 

이런 오해로 인해 앞글자를 소문자화하여 스프링 컨테이너에서 빈이름으로 찾는 로직을 작성하였고 예상하

지 못한 실패를 만나게 되었습니다.

 

앞으로 빈 이름으로 컨테이너에서 가져올 일이 있다면 Instrospector 클래스의 decapizlizae 메서드로 클래스의 이름을 컨벤션에 맞도록 변환한 뒤 가져올 수 있을 것 같습니다.

 

 

참고자료

https://download.oracle.com/otn-pub/jcp/7224-javabeans-1.01-fr-spec-oth-JSpec/beans.101.pdf?AuthParam=1730612779_1eabd53971cde79e32822516e6503560