du.study기록공간

@Value는 어디서 set이 되는걸까? 본문

스프링

@Value는 어디서 set이 되는걸까?

du.study 2020. 4. 5. 00:40
728x90

프로젝트에서 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 찾아보면 바로 나올듯)

 

 

 

 

 

728x90
Comments