Bean 생성 추적해보기
Spring core를 공부해보겠답시고 빌드한 뒤 소스코드를 두서없이 읽고만 있으려니, 진행이 안 되는 느낌이 들었다.
여긴 뭐고 저긴 또 뭔지...
그래서 실제로 앱을 실행한 뒤 추적하는 방법을 사용해보기로 하였다.
core에 대해서 공부를 한 덕분에 추적 경로를 만들어서 디버깅을 할 수 있었다.
먼저, Spring boot 2 이상 버전을 사용하여 프로젝트를 생성해보자.
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
main은 위의 코드처럼 생성되었을 것이다.@SpringBootApplication
은 알아서 셋팅을 다 해주므로 추적하는 데에는 필요가 없으니 가차없이 삭제한다.
텅 빈 main 메소드만 남기고 다 지워보자.
public class DemoApplication {
public static void main(String[] args) {
}
}
이 상태에서 시작해보자.
Bean 생성이 어디서 일어나는지 정확히는 몰라도 괜찮다.
Spring core 관련 정보를 찾다보면 BeanFactory가 bean을 관리하고, 가장 많이 사용되는 BeanFactory의 하위 인터페이스는 ApplicationContext
라는 것을 찾아볼 수 있다.
DemoRepository.java, DemoService.java, DemoConfiguration.java를 생성하고 아래처럼 작성했다.
이 객체들은 bean으로 등록할 것이다.
@Repository
public class DemoRepository {
}
@Service
public class DemoService {
private DemoRepository beanRepository;
public DemoService(DemoRepository beanRepository) {
this.beanRepository = beanRepository;
}
}
@Configuration
public class DemoConfiguration {
@Bean
public DemoRepository beanRepository() {
return new DemoRepository();
}
@Bean
public DemoService beanService(DemoRepository beanRepository) {
return new DemoService(beanRepository);
}
}
DemoService는 DemoRepository를 참조하는 형태이고, DemoConfiguration에서 나머지 둘의 bean을 생성하고 있다.
준비는 다 됐고, main을 채워주자.
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(DemoConfiguration.class);
String[] beanNames = context.getBeanDefinitionNames();
for (String name : beanNames) {
System.out.println(name);
}
직접 ApplicationContext를 생성하였다.
DemoConfiguration
파일에 @Bean
으로 설정한 객체를 bean으로 등록하도록 유도했다.
AnnotationConfigApplicationContext
는 @Configuration
annotation을 활용하여 bean을 만드는 구현체이다.
정상적으로 실행되었다면 아래의 log가 콘솔에 나타날 것이다.
00:11:33.724 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@18ef96
00:11:33.741 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
00:11:33.872 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
00:11:33.874 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
00:11:33.876 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
00:11:33.877 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
00:11:33.882 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'demoConfiguration'
00:11:33.888 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'demoRepository'
00:11:33.902 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'demoService'
00:11:33.907 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Autowiring by type from bean name 'demoService' via factory method to bean named 'demoRepository'
00:11:33.920 [main] DEBUG org.springframework.core.env.PropertySourcesPropertyResolver - Found key 'spring.liveBeansView.mbeanDomain' in PropertySource 'systemProperties' with value of type String
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
demoConfiguration
demoRepository
demoService
이 로그로 알 수 있는 정보가 여러 개 있다.
- Bean 생성 기본 정책은 Singleton이다.
BeanFactory
구현체DefaultListableBeanFactory
에서 bean을 생성한다.- 의존성 문제가 발생하지 않는 순서대로 bean을 생성하는 것으로 보인다. demoConfiguration, demoRepository, demoService 순으로 로그가 찍혀있다.
- beanService엔 생성자로 bean을 주입받도록 설정한 클래스이다.
DefaultListableBeanFactory
는 bean을 생성할 때 생성자에 알맞은 bean을 찾아 주입한다.
context 라인에 브레이크 포인트를 걸고 소스코드를 추적하면 더 자세한 정보를 알 수 있다.
AnnotationConfigApplicationContext
의 생성자에선 3가지 동작을 수행한다.
- Bean 관련 정책 설정
- Bean 등록
- refresh
추적을 계속 해보면AnnotationConfigApplicationContext
의 인수로 넘겨준 DemoConfiguration
은 Bean 등록 시 먼저 등록된다.
나머지 bean들은 refresh 단계에서 finishBeanFactoryInitialization
메소드를 실행할 때 싱글턴으로 생성되는 것을 알 수 있다.
역시 모를때는 디버깅으로 추적하는 것이 제일 편한 방법인 것 같다.
'Java > Spring framework' 카테고리의 다른 글
Spring framework core (4) - Environment (0) | 2020.01.12 |
---|---|
Spring framework core (3) - Bean scope (0) | 2020.01.12 |
Spring framework core (2) - ApplicationContext (0) | 2020.01.05 |
Spring framework core (1) IoC Container와 Bean (0) | 2020.01.05 |
Spring framework 소스 코드 읽어보기 첫 단계 - download, build (0) | 2019.12.31 |