SpringApplication은 main() 메서드에서 시작되는 스프링 어플리케이션의 초기 설정을 제어할 수 있는 클래스이다.
일반적으로는 main() 메서드 안에서 어플리케이션의 실행을 SpringApplication.run() 메서드에게 위임하거나, SpringApplication 객체를 만들어 run() 메서드를 실행할 수 있다.

public static void main(String[] args) {
    SpringApplication.run(MySpringConfiguration.class, args); // static 메서드로 기동
}
public static void main(String[] args) {
    SpringApplication app = new SpringApplication(App.class); // 객체를 생성하여 기동
    app.run(args);
}

 

SpringApplication이 초기화 되면서 어플리케이션이 구동될 때 발생하는 이벤트나 에러시 동작하는 FailureAnalyzer 등에 대해 먼저 알아본다. 


FailureAnalyzers

어플리케이션 실행시 오류가 발생한 경우에 동작하며, 에러에 대한 내용과 에러를 고치기 위한 Action을 출력한다.
이미 많은 FailureAnalyzers가 등록되어 있고, 추가도 가능하다.

***************************
APPLICATION FAILED TO START
***************************

Description:
Embedded servlet container failed to start. Port 8080 was already in use.

Action:
Identify and stop the process that's listening on port 8080 or configure this application to listen on another port.

Application Events and Listeners

스프링에서 제공하는 ContextRefreshedEvent 외에도 스프링부트의 SpringApplication은 추가적인 어플리케이션 이벤트들을 보낸다.
어플리케이션 기동이 시작되면 각 단계에 따라서 ApplicationStartingEvent를 시작으로 이벤트들이 발생하고, 발생된 이벤트들은 이벤트리스너에 전달된다. 각 단계별로 어떤 이벤트가 발생하는지는 아래 스프링부트 공식문서를 참고하자.

https://docs.spring.io/spring-boot/docs/2.2.2.RELEASE/reference/html/spring-boot-features.html#boot-features-application-events-and-listeners

 

이벤트리스너가 빈으로 등록되어 있고, 리스너의 표적 이벤트가 발생하면 자동으로 처리메서드가 실행된다.
아래 코드와 로그는 빈으로 등록된 ApplicationStartedEvent리스너가 어플리케이션 기동시 출력된 로그이다.
SampleListener 클래스가 @Component 애노테이션으로 빈등록 되었으며, 기동시 ApplicationStartedEvent 이벤트가 발생하면서 자동으로 onApplicationEvent() 메서드가 호출된다.

@Component // 빈으로 등록한다.
public class SampleListener implements ApplicationListener<ApplicationStartedEvent> {
    @Override
    public void onApplicationEvent(ApplicationStartedEvent applicationStartedEvent) {
        System.out.println("ApplicationStartedEvent가 발생!");
    }
}

어플리케이션 기동시 마지막에 콘솔로그가 출력된다. (ApplicationStartedEvent가 기동시 제일 마지막에 발생하기 때문이다.)

2019-12-26 16:09:49.823 INFO 4212 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2019-12-26 16:09:49.828 INFO 4212 --- [ main] com.yang.wind.App : Started App in 2.1 seconds (JVM running for 3.235)
ApplicationStartedEvent가 발생!

하지만 ApplicationStartingEvent의 경우 ApplicationContext가 초기화 되기 전에 발생하는 이벤트기 때문에, 빈 등록으로는 리스너가 동작하지 않는다.(ApplicationContext에 빈이 등록되는데, 이 과정보다 먼저 이벤트가 발생하므로 이벤트 발생시점에는 리스너가 있는지도 모르는 상태이다.) 이런 경우에는 SpringApplication addListeners() 메서드로 리스너를 추가하면 된다.
아래 코드는 SpringApplication.run()으로 바로 시작하지 않고, 객체 생성을 통해 설정을 추가했다.

@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(App.class);
        app.addListeners(new SampleListener()); // 리스너를 코드로 추가한다.
        app.run(args);
    }
}
// 이미 SpringApplication에 리스너를 등록했으므로 빈등록이 필요없다.
public class SampleListener implements ApplicationListener<ApplicationStartingEvent> {
    @Override
    public void onApplicationEvent(ApplicationStartingEvent applicationStartingEvent) {
        System.out.println("ApplicationStartingEvent 발생!");
    }
}

어플리케이션 기동시 처음에 콘솔로그가 출력된다. 로그를 복붙하다보니 좀 깨지지만 그건 중요한게 아니다.

ApplicationStartingEvent 발생!

  .   ____          _            __ _ _

 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \

( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \

 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )

  '  |____| .__|_| |_|_| |_\__, | / / / /

 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::        (v2.2.0.RELEASE)

....


WebApplicationType

SpringApplication에서는 ApplicationContext의 타입이 내부적으로 확정된다.
3개의 타입이 존재하는데 다음과 같이 자동설정되며 SpringApplication의 setWebApplicationType() 메서드를 이용하여 코드에서 특정타입으로 오버라이드가 가능하다.

  • WebApplicationType.SERVLET : Spring MVC가 존재하면 설정됨
  • WebApplicationType.REACTIVE : Spring MVC가 없고, Spring WebFlux가 존재하면 설정됨
  • WebApplicationType.NONE : 위의 경우에 해당이 안되면 설정됨. 어플리케이션이 기동 되었다가 바로 종료된다.
@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(App.class);
        // ApplicationType 설정을 오버라이드 한다.
        app.setWebApplicationType(WebApplicationType.SERVLET);
        app.run(args);
    }
}

+ Recent posts