b

Spring Boot 가 실행될 때의 메소드를 실행하는 여러가지 방법과 Started ... 로깅의 위치 본문

카테고리 없음

Spring Boot 가 실행될 때의 메소드를 실행하는 여러가지 방법과 Started ... 로깅의 위치

dev.bistro 2020. 4. 28. 09:20

오래된 배치를 마이그레이션하고 있다.  SpringBatch 를 쓰지 않고 여러개의 SpringBootApplication 을 하나의 프로젝트에 만들어  

manifest {
        attributes(
                'Main-Class': 'org.springframework.boot.loader.PropertiesLauncher'
        )
    }
    

PropertiesLauncher를 이용해 java -Dloader.main=BatchName -jar jarName.jar 이렇게 실행하고 있다.

이렇게 실행하면 배치Job 에 해당하는 Class를 실행하기 위해서는  @PostConstruct가 가장 간편하고 요즘 개발에게 익숙한 방법이다.

SpringBatch는  JobLauncherCommandLineRunner 를 이용해서 Job을 수행해주지만, 
SpringBoot Application은 여러가지 방법이 있으므로, 그 중 하나인 @PostConstruct를 이용해서 배치 메인 로직이 수행되게 하였다.

이렇게 실행해보면 아래처럼, @PostConstruct 에 해당하는 부분이 모두 실행되고 나서야, Application 이 시작되었다고 로깅이 남는다.

2020-04-28 09:18:28.036  WARN 72741 --- [           main] o.m.s.mapper.ClassPathMapperScanner      : No MyBatis mapper was found in '[com.elevenst.push.batch.job.duplicate_msg_delete]' package. Please check your configuration.
Main
2020-04-28 09:18:28.643  INFO 72741 --- [           main] e.p.b.j.d.DuplicateMessageDeleteBatchApp : Started DuplicateMessageDeleteBatchApp in 1.316 seconds (JVM running for 1.608)

 

로그를 어느 단계에서 찍길래 @PostConstruct 실행 이후에 저런 로그가 남는 것일까?

"Started " 이라는 문자열을 찾아서 검색해보면 Info Level 일 경우에 https://git.io/JfqNE 부분에서 StringBuilder를 이용해서 로그가 찍히는 걸 볼 수 있다. 
Intellij hierarchy 기능을 이용해서 누가 호출했는지를 따라가보면  아래와 같은 로직을 볼 수 있다.

 

로그를 찍는 바로 아래 부분에 listeners 를 이용할 수 있을까 봤더니, SpringApplicationRunListeners class 는  접근자도 없이, 재사용을 위한 클래스가 아니다 https://git.io/JfqNi  
물론 같은 패키징안에 클래스를 만들어 extends 할 수는 있지만 그렇게까지 할 이유는 없다.  하지만 이 클래스 안에서는 SpringApplicationRunListener 라는 인터페이스를 member로 가지고 메소드를 위임해서 호출 하는 것을 볼 수 있다.  그리고 그 유일한 구현체는 그 유명한 EventPublishingRunListener https://git.io/JfqNj

사족이지만 그 다음에 위치한 callRunners 를 보면, ApplicationRunner 인터페이스를 추적해서 먼저 실행 하고 그 다음 CommandLineRunner 를 실행 한다. 이 순서는 처음 알았네.

결론적으로는 @PostConstruct보다는 listeners.running(context) 에서 수행 될 수 있는 형식이 더 올바른 것 같다.

    // @PostConstruct 보다는
    @EventListener(ApplicationReadyEvent.class)
    public void run() {
        System.out.println("Main");
    }
    
    --output--
    2020-04-28 09:17:42.874  INFO 72718 --- [           main] e.p.b.j.d.DuplicateMessageDeleteBatchApp : Started DuplicateMessageDeleteBatchApp in 1.607 seconds (JVM running for 1.974)
Main

 

한 줄 요약 : Spring Boot Application 에서 Context가 전체 로딩된 이후에 실행하려면 @PostConstruct 보다는 @EventListener or  ApplicationListener<ApplicationReadyEvent> 를 쓰자.

Comments