@Value
를 사용하여 아래의 url
필드에 값을 주입하려고 했다.
@Component
public class AwsS3Proxy {
//
@Value(“${aws.s3.url:https://bucket.s3-ap-southeast-1.amazonaws.com}”)
private String url;
}
그리고 주입될 값을 application.yml에 넣어주었다.
aws:
s3:
url: https://inject-value.com
그런데 값이 주입되지 않아서 null로 뜨는 문제가 발생하였다.
@Component
어노테이션을 붙여서 Bean으로 등록도 했고, application.yml에 해당되는 값도 넣어주었는데 왜 값이 주입되지 않았을까?
원인은 @Value
를 통해 값을 주입 받아야 하는 클래스가 컴포넌트 스캔 범위에 없었기 때문이다.
당시의 상황을 좀 더 자세히 살펴보자.
위의 그림을 살펴보면 @Value
를 통해 값을 주입할 필드를 가지고 있는 AwsS3Proxy
는 공통 라이브러리에 있는 클래스이다.
그리고 service라는 프로젝트는 공통 라이브러리를 사용하는 입장으로 application.yml
을 통해 값을 주입해주는 곳이다.
이때 service 프로젝트가 컴포넌트를 스캔하는 범위는 com.heritage.service이다.
그런데 @Value
로 값을 주입하고자 하는 클래스의 경로는 com.heritage.common.config이다.
이처럼 service 프로젝트가 컴포넌트를 스캔하는 범위에 해당 클래스가 없었기 때문에 application.yml에 값이 있어도 주입할 수 없었던 것이다.
오류의 원인을 찾았으니 이제 컴포넌트를 스캔하는 범위에 해당 클래스를 추가해주면 될 것이다.
컴포넌트 스캔 범위는 어떻게 조정할 수 있을까?
아래와 같이 EnableAutoConfiguration
을 사용하면 Spring에게 컴포넌트 스캔 범위를 알려줄 수 있다.
먼저 AwsS3Proxy
를 Bean으로 등록해주는 Configuration 클래스를 작성한다.
@Configuration
@ComponentScan("com.heritage.common.config")
public class CommonConfiguration {
@Bean
public AwsS3Proxy awsS3Proxy() { return new AwsS3Proxy(); }
}
그 다음 main/resources
경로에 META-INF
디렉토리를 추가하고, 아래와 같이 작성한 spring.factories
파일을 넣어준다.
org.springframework .boot.autoconfigure.EnableAutoConfiguration =\
com.heritage.common.config.CommonConfiguration
그러면 값이 정상적으로 주입되는 것을 발견할 수 있을 것이다.
프로젝트의 Entry point에는 @SpringBootApplication
어노테이션을 붙여준다.
이 어노테이션을 타고 들어가보면 @SpringBootApplication
은 아래와 같이 구현되어 있다.
@Target(value=TYPE)
@Retention(value=RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters={@ComponentScan.Filter(type=CUSTOM,classes=TypeExcludeFilter.class),})
public @interface SpringBootApplication
즉, 다음 세 가지 어노테이션의 기능을 포함하고 있는 것이다.
@EnableAutoConfiguration
@ComponentScan
@Configuration
이 중 @EnableAutoConfiguration
은 jar dependencies를 바탕으로 자동으로 Spring 환경을 설정해주는 어노테이션이다.
예컨대 classpath에 tomcat-embedded.jar가 있으면 TomcatServletWebServerFactory가 필요할 것으로 판단하여 자동으로 Bean으로 등록해주는 식이다.
관련하여 자세한 내용은 아래 공식문서에서 볼 수 있다.
Using the @SpringBootApplication Annotation