[05] SpringApplication Class

17832 단어 Spring bootSpring boot

❓ SpringApplication

이전의 Main Application Class의 main 메서드에서 애플리케이션을 실행하기 위해 SpringApplication 클래스의 run 메서드를 호출하였다.

@SpringBootApplication
public class MyApplication {

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }

}

--

🌌 구동 실패 (Startup Failure)

애플리케이션 시작에 실패하면, 등록된 "FailureAnalyzers"는 특정 에러 메시지를 보여주고 문제를 해결하도록 해준다. 만약 예외를 처리할 "FailureAnalyzers"이 없으면, debug 속성이나 DEBUG 로깅을 활성화해야 한다.

$ java -jar myproject.jar --debug

--

🌌 지연 초기화 (Lazy Initialization)

SpringApplication 클래스는 애플리케이션을 지연 초기화되는 것을 허용한다. 지연 초기화가 허용되면, Spring Bean들은 애플리케이션이 시작할 때가 아니라 필요해질때 생성된다. 따라서 지연 초기화를 활성화하면 애플리케이션을 시작하는 시간을 줄일 수 있다. 웹 애플리케이션에서는 HTTP 요청을 받을 때까지 웹 관련 Bean들을 초기화하지 않는다.

지연 초기화는 SpringApplicationBuilder 클래스의 "lazyInitialization" 메서드나 SpringApplication 클래스의 "setLazyInitailization" 메서드를 사용하여 활성화할 수 있다. 또한, 아래와 같이 속성으로도 활성화 가능하다.

spring.main.lazy-initialization=true

--

🌌 Fluent Builder API

ApplicationContext 계층을 구축하거나 "fluent" buidler API를 사용하는 것을 선호하면, SpringApplicationBuilder 클래스를 사용할 수 있다.

SpringApplicationBuilder 클래스는 다수의 메서드 호출을 묶어 주고, 계층을 만드는 "parent"와 "child" 메서드들을 포함한다.

new SpringApplicationBuilder()
        .sources(Parent.class)
        .child(Application.class)
        .bannerMode(Banner.Mode.OFF)
        .run(args);

--

🌌 애플리케이션 가용성 (Application Availability)

애플리케이션이 플랫폼에 deploy될 때, "Kubernetes Probes" 같은 인프라로 애플리케이션의 가용성에 대한 정보를 플랫폼에게 제공할 수 있다. Spring Boot는 일반적으로 "liveness"와 "readiness" 가용성 상태에 대한 지원을 제공한다. Spring Boot의 "Acuator" 지원을 이용한다면, 이 두가지의 가용성 상태들은 'health endpoint groups'로써 표현된다.

추가로 ApplicationAvailability 인터페이스를 Bean들에 주입하여 가용성 상태들을 확인할 수 있다.

1) Liveness State

"Liveness" 상태는 애플리케이션의 내부 상태가 올바르게 작동하는지, 아니면 현재 장애가 있는 경우 자체적으로 복구할 수 있는지 여부를 알려준다. 깨진 "Liveness" 상태는 애플리케이션이 복구할 수 없는 상태이며, 인프라가 애플리케이션을 다시 시작해야 한다는 것을 의미한다.

애플리케이션의 내부 상태는 주로 Spring ApplicationContext 클래스로 표현된다. 만약 ApplicationContext가 성공적으로 시작한다면, Spring Boot는 애플리케이션이 올바른 상태에 있다고 추정한다. Context를 새로고침 하자마자 애플리케이션이 "live"로 간주된다.

2) Readiness State

"Readiness" 상태는 애플리케이션이 트래픽(traffic)을 처리할 준비가 됬는지 알려준다. 실패한 "Readiness" 상태는 현재 애플리케이션에 트래픽을 라우팅(route)하면 안된다는 것을 알려준다. 실패한 "Readiness" 상태는 주로 [1]시작 중에, [2]CommandLineRunner이나 ApplicationRunner 컴포넌트가 처리되는 중에, 또는 [3]추가적인 트래픽을 처리하기에 너무 빠쁜 상태라고 판달할 때 발생한다.

ApplicationRunner이나 CommandLineRunner가 호출되자마자 애플리케이션이 "ready"로 간주된다.

3) 가용성 상태 관리

애플리케이션 컴포넌트들은 ApplicationAvailabilty 인터페이스를 주입하여 언제든지 현재 가용성 상태를 확인할 수 있다. 빈번히, 애플리케이션은 상태 업데이트 알림을 받거나 애플리케이션의 상태를 업데이트하기를 원한다.

예를 들어, 애플리케이션의 "Readiness" 상태를 파일로 내보내서 Kubernetes "exec Probe"에서는 이 파일을 볼 수 있다.

@Component
public class MyReadinessStateExporter {

    @EventListener
    public void onStateChange(AvailabilityChangeEvent<ReadinessState> event) {
        switch (event.getState()) {
        case ACCEPTING_TRAFFIC:
            // create file /tmp/healthy
            break;
        case REFUSING_TRAFFIC:
            // remove file /tmp/healthy
            break;
        }
    }

}

또한 애플리케이션에 오류가 발생하고 복구를 못 할때 애플리케이션의 상태를 업데이트할 수 있다.

@Component
public class MyLocalCacheVerifier {

    private final ApplicationEventPublisher eventPublisher;

    public MyLocalCacheVerifier(ApplicationEventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
    }

    public void checkLocalCache() {
        try {
            // ...
        }
        catch (CacheCompletelyBrokenException ex) {
            AvailabilityChangeEvent.publish(this.eventPublisher, ex, LivenessState.BROKEN);
        }
    }

}

--

🌌 Events & Listeners

"ContextRefreshedEvent" 같은 Spring Framework 이벤트뿐만 아니라 SpringApplication 클래스는 추가적인 애플리케이션 이벤트들을 보낸다.

다음과 같은 순서로 애플리케이션이 구동될 때, 애플리케이션 이벤트들이 보내진다.

순서이벤트설명
1ApplicationStartingEventListeners와 Initializers를 제외한 모든 처리 이전에 구동 시작 시점에 보낸다.
2ApplicationEnvironmentPreparedEventContext가 생성되기 이전에 Context에서 사용되는 Environment를 알릴 때 보낸다.
3ApplicationcontextInitializedEventBean 정의들이 불려지기 전에 ApplicationContext가 준비 되고 ApplicationcontextInitializers가 호출될 때 보낸다.
4ApplicationPreparedEventBean 정의들이 불려진 후에 refresh가 시작하기 직전에 보낸다.
5ApplicationStartedEventApplicationRunner와 CommandLineRunner가 호출되기 전, Context가 refresh된 후에 보낸다.
6AvailabilityChangeEventLivenessState.CORRECT와 함께 전송되어 애플리케이션이 Live 상태임을 알린다.
7ApplicationReadyEventApplicationRunner와 CommandLineRunner가 호출된 후에 보낸다.
8AvailabilityChangeEventReadinessState.ACCEPTING_TRAFFIC와 함께 전송되어 애플리케이션이 요청을 처리할 준비가 되어있음을 알린다.
9ApplicationFailedEvent시작 중에 오류가 있으면 보낸다.

추가로, ApplicationPreparedEvent 이후 그리고 ApplicationStartedEvent 이전에 다음의 이벤트들이 보내진다.

  • WebServerInitializedEvent : WebServer가 준비된 후에 보낸다.
  • ContextRefreshedEvent : ApplicationContext가 refresh될 때 보낸다.

애플리케이션 이벤트들은 Spring Framework의 이벤트 발행 기술을 사용하여 보낸다. 이 기술의 일부는 자식 Context 내 Listener들에 발행된 이벤트들이 조상 Context들 내 Listener로 전파되는 것을 보장한다. 만약 애블리케이션이 SpringApplication 인스턴스들의 계층을 사용한다면, Listener는 동일 유형의 애플리케이션 이벤트를 여러 인스턴스로 받을 수 있다.

--

🌌 웹 환경

SpringApplication 클래스는 올바른 종류의 ApplicationContext 생성하도록 시도한다.

다음은 WebApplicationType을 결정하는 알고리즘이다.

  • 만약 Spring MVC가 존재하면, AnnotationConfigServletWebServerApplicationContext가 사용된다.
  • 만약 Spring MVC가 존재하지 않고 Spring WebFlux가 존재하면, AnnotationConfigReactiveWebServerApplicationContext가 사용된다.
  • 다른 경우에는, AnnotationConfigApplicationContext가 사용된다.

setWebApplicationtype(WebApplicationType) 메서드를 호출하여 덮어쓸 수 있다.

--

🌌 애플리케이션 인수 접근

SpringApplication.run(...)을 통과한 애플리케이션 인수들에 접근하고 싶다면, ApplicationArguments 빈에 주입할 수 있다. ApplicationArguments 인터페이스는 String 배열 인수들뿐 만 아니라 option과 non-option으로 구분된 인수들에 접근을 제공한다.

@Component
public class MyBean {

    public MyBean(ApplicationArguments args) {
        boolean debug = args.containsOption("debug");
        List<String> files = args.getNonOptionArgs();
        if (debug) {
            System.out.println(files);
        }
        // if run with "--debug logfile.txt" prints ["logfile.txt"]
    }

}

--

🌌 ApplicationRunner & CommnadLineRunner

SpringApplication 클래스가 시작되고 특정 코드를 실행하려면, ApplicationRunner 혹은 CommandLineRunner 인터페이스를 실행할 수 있다. 두 인터페이스 모두 같은 방법으로 동작하고 SpringApplication.run(...) 메소드가 완료된 바로 직후 불려지는 하나의 run 메서드를 제공한다.

CommandLineRunner 인터페이스는 애플리케이션 인수들을 String 배열로 받고, ApplicationRunner 인터페이스는 ApplicationArguments 객체로 받는다.

@Component
public class MyCommandLineRunner implements CommandLineRunner {

    @Override
    public void run(String... args) {
        // Do something...
    }

}

--

🌌 시작 추적 (Startup Tracking)

애플리케이션이 시작할 동안, SpringApplication 클래스와 ApplicationContext 클래스는 애플리케이션 주기(lifecycle)와 관련된 많은 작업들을 수행한다. ApplicationStartup 클래스로 애플리케이션 시작 순서를 추적할 수 있다.

1) FlightRecorderApplicationStartup

BufferingApplicationStartup 구현 클래스는 시작

@SpringBootApplication
public class MyApplication {

    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(MyApplication.class);
        application.setApplicationStartup(new BufferingApplicationStartup(2048));
        application.run(args);
    }

}

💦 다음으로 외부화된 설정을 파혜쳐보자~

좋은 웹페이지 즐겨찾기