반응형
CommandLineRunner
Spring Boot의 초기 설정 과정의 마지막에 실행되는 메서드를 정의한 인터페이스
- Runner 인터페이스를 상속한 인터페이스
아래의 메서드를 정의하고 있다.
void run(String... args) throws Exception;
ApplicationRunner
마찬가지로 Spring Boot의 초기 설정 과정의 마지막에 실행되는 메서드를 정의한 인터페이스
- Runner 인터페이스를 상속한 인터페이스
아래의 메서드를 정의하고 있다.
void run(ApplicationArguments args) throws Exception;
차이점
둘의 차이점은 메서드 시그니처에서 매개변수 타입이 다른 것 밖에는 없다.
- ApplicationArguments는 argument를 조회하는 편의 메서드들을 가지고 있다.
사용 방법
- 빈으로 등록된 클래스를 구현해준다. (@Component와 하위 어노테이션들이 붙은 클래스)
- 위의 두 인터페이스를 구현해준다.
- 필요한 작업을 run() 메서드에 구현해준다.
그럼 Spring Boot는 초기화 작업 마지막에 run()메서드를 호출해준다.
실행 순서
1. Spring Boot application 실행 (SpringApplication.run() 호출)
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
2. run() 메서드 구현의 하단 부분에 callRunners(context, applicationArguments) 호출
위에서 언급한 run() 메서드 호출을 따라가다 보면 Spring Boot 초기화 세부 구현이 정의된 run() 메서드가 나온다.
이 메서드의 하단 부분에 보면 callRunners() 메서드를 호출하는 것을 볼 수 있다.
public ConfigurableApplicationContext run(String... args){
...
refreshContext(context);
afterRefresh(context, applicationArguments);
startup.started();
if (this.properties.isLogStartupInfo()) {
new StartupInfoLogger(this.mainApplicationClass, environment).logStarted(getApplicationLog(), startup);
}
listeners.started(context, startup.timeTakenToStarted());
callRunners(context, applicationArguments); // 여기!
...
}
3. callRunners() 내부 구현
Runner.class타입의 빈들의 이름을 조회한다.- 빈들의 이름으로
Runner.class타입의 인스턴스들을 조회한다. @Order에 정의된 우선순위로 실행할 Runner들의 순서를 조회한다. (Comparator)- Runner들을 정렬하고 callRunner()를 호출한다.
private void callRunners(ConfigurableApplicationContext context, ApplicationArguments args) {
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
String[] beanNames = beanFactory.getBeanNamesForType(Runner.class); // 1
Map<Runner, String> instancesToBeanNames = new IdentityHashMap<>(); // 2
for (String beanName : beanNames) {
instancesToBeanNames.put(beanFactory.getBean(beanName, Runner.class), beanName);
}
Comparator<Object> comparator = getOrderComparator(beanFactory) // 3
.withSourceProvider(new FactoryAwareOrderSourceProvider(beanFactory, instancesToBeanNames));
// 4
instancesToBeanNames.keySet().stream().sorted(comparator).forEach((runner) -> callRunner(runner, args));
}
4. callRunner() 내부 구현
- 만약 Runner가 ApplicationRunner라면, 그대로 메서드를 호출한다.
- 만약 Runner가 CommandLineRunner라면, ApplicationArguments를 문자열 배열로 만들어 메서드를 호출한다.
private void callRunner(Runner runner, ApplicationArguments args) {
if (runner instanceof ApplicationRunner) { // 1
callRunner(ApplicationRunner.class, runner, (applicationRunner) -> applicationRunner.run(args));
}
if (runner instanceof CommandLineRunner) { // 2
callRunner(CommandLineRunner.class, runner,
(commandLineRunner) -> commandLineRunner.run(args.getSourceArgs()));
}
}반응형
'Spring' 카테고리의 다른 글
| [JPA] JPA의 entity 상태와 영속성 컨텍스트의 기능들 (1) | 2025.05.26 |
|---|---|
| [Spring WebSocket] Spring WebSocket에서 STOMP를 사용해보자~~ (2) | 2024.12.09 |
| [Spring Boot] 등록 요청의 중복 방지하기, 멱등성 보장 (0) | 2024.08.01 |
| [Spring Boot] 스프링 동시성 제어하기 (Java Synchronized keyword) (2) | 2024.04.25 |
| [Spring Boot] Spring Boot에서 JPA QueryDSL 적용 방법 (3) | 2024.04.17 |