일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- HashMap
- asyncconfigurer
- ResponseBody
- traceId
- map
- list
- traceasynccustomautoconfiguration
- elasticsearch
- b3-propagation
- java lambda
- awssecretsmanagerpropertysources
- java.util.list
- CompletableFuture
- DeferredImportSelector
- Spring JPA
- @FunctionalInterface
- java list
- Spring Boot
- asynccustomautoconfiguration
- kotlin
- EnableWebMvc
- spring MVC
- aws secretmanager
- spring
- spring3 spring2 traceid
- jpa
- micrometer tracing
- Sleuth
- SpringMVC
- java
- Today
- Total
du.study기록공간
@Value는 어디서 set이 되는걸까? 본문
프로젝트에서 reousrce로 등록한 데이터를 @value를 통해서 데이터를 받아 사용하고 있습니다.
이 기능 덕분에 각 존별로 다른데이터를 코드의 분기처리없이 사용하고 있습니다.
@Configuration
public class Config {
@Value("${test.value}")
private String test;
}
여기서 든 첫번째 궁금증..
1. 어디서 예를 set해주는걸까?
우선 결론부터 작성하면 빈 생성과정에서 AutowiredAnnotationBeanPostProcessor 해당 프로세서를 보는 과정에서 postProcessProperties 메서드의 metadata.inject(bean, beanName, pvs); 호출을 통해 @Value가 inject가 됩니다.
좀 더 과정을 적어본다면 ( 사이사이 생략이 좀 있다.. 너무 과정이 길다.)
1. (SpringBoot로 확인시 AbstractApplicationContext).refresh() 호출 (AnnotationConfigServletWebServerApplicationContext)
2. refresh -> finishBeanFactoryInitialization() 호출
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
3. AbstractAutowireCapableBeanFactory 에서 createBean 호출
4. createBean 과정 중, AutowiredAnnotationBeanPostProcessor ->postProcessProperties 호출
5. metadata.inject(bean, beanName, pvs); 호출 ( 드디어 메인에 다다르고 있다.. inject에서 감이온다.)
6. inject메서드에서 해당 코드 호출 ( 여기서 받아오는 value를 통해 set해준다.)
try {
value = AutowiredAnnotationBeanPostProcessor.this.beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
6. resolveDependency에 의하여 DefaultListableBeanFactory로 접근,
7. DefaultListableBeanFactory 에 접근 String strVal = this.resolveEmbeddedValue((String)value);호출을 통하여 value 리턴 (PropertySourcesPlaceholderConfigurer 메서드 호출)
StringValueResolver valueResolver = strVal -> {
String resolved = (this.ignoreUnresolvablePlaceholders ?
propertyResolver.resolvePlaceholders(strVal) :
propertyResolver.resolveRequiredPlaceholders(strVal));
if (this.trimValues) {
resolved = resolved.trim();
}
return (resolved.equals(this.nullValue) ? null : resolved);
};
해당 값을 리턴받아 최종적으로 @Value("${test.value}")에 매핑..!
간략하게 정리하면, @Value를 가진 Bean이 호출되는 시점 ( 다른 클레스에서 해당 Bean을 @Autowired )에 createBean을 하게되고, 해당과정에서 다시 dependency 조사를 하는 과정에서 @Value를 찾아 set 하게된다.
진짜 간단하게 resource 를 사용하고 있었지만.. 세부적으로 거의 10~20단계를 거쳐서 set되고 있었다.
이렇게 간단하게 사용하도록 만들어주신 개발자 분들에게 다시한번 존경 + 10000 드립니다.
다음번에 좀 찾아봐야 할 것들
1. refresh() 의 각 기능들....(천천히 하나씩.. 찾아봐야겠다.)
2. resource가 set되는 과정 ( PropertySourcesPlaceholderConfigurer 찾아보면 바로 나올듯)
'스프링' 카테고리의 다른 글
Spring boot Web embedded Container(server) 변경 (0) | 2020.05.10 |
---|---|
Spring boot @SpringBootApplication (0) | 2020.05.07 |
Spring Boot 시작하기. (0) | 2020.03.17 |
@Controller handlerMethod register (0) | 2020.03.07 |
Spring을 사용하는 서버에서 CORS 설정 과정에서 발생한 이슈들 (0) | 2020.02.10 |