요즈음 재미로 Spring의 Controller를 모방하던 도중 Request가 올때마다 new Instance()를 통하여 매번 Class (Controller 객체) 를 생성 해야했다.
너무 비효율적이라고 느꼇고 나중에 BeanFactory도 만들어야겠다는 생각을 가지게됐다.
BeanFactory의 동작원리는 알았지만 Spring은 어떻게 효과적으로 관리할까? 라는 의문이 생겨서 소스를 뜯어보았다.
바로 알아보도록 하겠다.
어떤식으로 동작하는지 이해하시기 위해서는 직접 디버깅 해보시는게 제일 좋습니다.
1. Spring Application Run
Spring Application을 실행하게 되면 main메소드가 실행되고 SpringApplication.run 을 실행하게 된다.
2. SpringApplictaion.run
SpringApplication Class의 run을 따라가다보면 아래와 같은 메소드가 등장한다.
우리가 보고자 하는 부분은 refreshContext 메소드안에 있다.
3. SpringApplication.refreshContext
refreshContext안에서는 refresh 메소드를 호출한다.
4. SpringApplication.refresh
refresh 메소드에서는 ApplicationContext의 refresh를 호출한다.
5. ServletWebServerApplicationContext.refresh
ApplicationContext의 refresh를 실행한다.
ApplicationContext는 SpringApplication.run에서 생성한다.
본론으로 돌아와서 ServletWebServerApplicationContext.refresh가 실행된다.
생성은 AnnotationConfigServletWebServerApplicationContext로 되는데 실행은 ServletWebServerApplicationContext 객체의 refresh가 실행되는 이유를 짐작이 안가시는분은 JAVA기초를 다시 한번 보시는 것을 추천 드리겠습니다.
ServletWebServerApplicationContext 에서는 super의 refresh를 호출하고 있습니다.
6. AbstractApplicationContext.refresh
우리가 알아보려는 Bean 등록의 핵심은 사실 여기부터 시작이다.
먼저 invokeBeanFactoryPostProcessors메소드를 알아보도록 하자.
7. AbstractApplicationContext.invokeBeanFactoryPostProcessors
PostProcessorRegistrationDelegate의 invokeBeanFactoryPostProcessors 메소드를 호출한다.
8. PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors
실제로 작업을 하는 메소드는 invokeBeanDefinitionRegistryPostProcessors 메소드이다.
9. PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors
BeanDefinitionRegistryPostProcessor의 postProcessBeanDefinitionRegistry 메소드를 호출합니다.
10. BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry
ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry이 실행되고 이 메소드안에서는 processConfigBeanDinitions 메소드가 실행된다.
11. ConfigurationClassPostProcessor.processConfigBeanDinitions
processConfigBeanDinitions메소드를 보게되면 ConfigurationClassParser의 parse 메소드를 실행하게된다.
12. ConfigurationClassParser.parse
BeanDefinition 의 type에 따라 원하는 parse를 호출한다.
우리가 살펴볼것은 첫번째 조건문에 있는 parse이다.
해당 parse를 실행하면 processConfigurationClass 메소드를 실행한다.
13. ConfigurationClassParser.processConfigurationClass
doProcessConfigurationClass 메소드를 실행한다.
14. ConfigurationClassParser.doProcessConfigurationClass
doProcessConfigurationClass 메소드에서 조금 내려보면 componentScanParser.parse가 보인다.
이제 드디어 componentScan이라는 단어가 보인다.
이제 빈 등록이 시작되겠구나 라고 추측할 수 있다.
하지만 여기서 등록하지 않는다는건 비밀...
15. ComponentScanAnnotationParser.parse
return 하는곳을 본다면 base package를 기반으로 scan을 진행한다.
16. ClassPathBeanDefinitionScanner.doScan
findCandidateComponents 메소드를 통하여 Bean으로 등록할 후보들을 찾아온다.
17. ClassPathBeanDefinitionScanner.findCandidateComponents
조건문에 따라 실행되는 메소드가 다릅니다.
여기서는 scanCandidateComponents 를 실행하게 됩니다.
18. ClassPathScanningCandidateComponentProvider.scanCandidateComponents
여기서는 Component로 등록할 수 있다면 등록할 수 있다고 정보를 등록합니다.
19. ClassPathScanningCandidateComponentProvider.isCandidateComponent
제외필터타입에 없고 포함필터타입에 있다면 등록할 수 있다고 return한다.
20. ClassPathScanningCandidateComponentProvider.scanCandidateComponents
Component로 등록할 수 있다면 등록할 수 있다고 정보를 등록합니다.
21. AbstractApplicationContext.finishBeanFactoryInitialzation
빈으로 등록될 객체들의 정보를 등록이 다 됐다.
하지만 아직 빈으로 등록되지는 않았다.
finishBeanFactoryInitialzation 메소드를 실행한다.
22. DefaultListableBeanFactory.finishBeanFactoryInitializion
실제로 Bean을 등록하는 작업을 수행하는 메소드는 preInstantiateSingletons 메소드다.
23. DefaultListableBeanFactory.preInstantiateSingletons
getBean 메소드를 실행하게 된다.
24. AbstractBeanFactory.getBean
getBean메소드 안에서는doGetBean 메소드를 다시 호출한다.
25. AbstractBeanFactory.doGetBean
doGetBean 메소드를 살펴보면 빈이 아직 등록되지 않았다면 빈을 생성하는 것을 볼 수 있다.
여기까지 긴 Bean등록 과정을 살펴보았다.
대략적인 순서와 커다란 역할만 적었다.
세세한 역할 및 자세한 사항은 직접 디버깅을 하시면서 분석하는 것을 추천드립니다.
'개발 > Spring' 카테고리의 다른 글
[Spring] @DataJpaTest (0) | 2021.03.14 |
---|---|
[Spring] Controller에 파라미터 바인딩은 어떻게 이루어질까 ? (0) | 2021.01.26 |
[Spring] Junit5로 예외테스트 하기 (0) | 2020.12.06 |
[Spring] PostgreSQL yml 설정 (0) | 2020.12.06 |
[Spring Batch] Scope 'job' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; (0) | 2020.11.16 |
댓글