SpringApplication.run

2024. 10. 16. 11:50Spring Boot/Spring Boot Auto Configuration

SpringApplication.run()은 Spring Boot 애플리케이션의 시작점에서 사용되는 메서드로, Spring Boot 애플리케이션을 실행하고 부트스트랩(초기화)하는 역할을 합니다. 이 메서드는 애플리케이션의 실행을 위한 여러 초기화 작업을 수행하며, Spring 컨텍스트를 생성하고 설정을 적용한 후에 애플리케이션을 실행할 준비를 마칩니다.

아래는 SpringApplication.run()의 동작 과정을 상세하게 설명한 내용입니다.

SpringApplication.run()의 주요 역할

  1. SpringApplication 객체 생성:
    • SpringApplication.run()은 내부적으로 SpringApplication 객체를 생성하고 이를 통해 애플리케이션을 부트스트랩합니다.
    • 이 객체는 애플리케이션 실행 중 필요한 환경 설정을 관리하고, 필요한 여러 가지 리스너, 초기화 작업, 애플리케이션 이벤트 등을 처리합니다.
  2. 애플리케이션 유형 결정:
    • SpringApplication은 애플리케이션이 웹 애플리케이션인지 비웹 애플리케이션인지 자동으로 감지합니다.
    • Spring Boot는 클래스패스에 서블릿 관련 라이브러리가 있는지 확인한 후, 웹 애플리케이션이면 내장된 톰캣, 제티 등의 서블릿 컨테이너를 설정하고 시작합니다.
  3. Spring 컨텍스트 생성:
    • Spring Boot는 애플리케이션의 ApplicationContext를 생성합니다. 이 컨텍스트는 Spring 프레임워크에서 빈(Bean)을 관리하고, 애플리케이션의 모든 설정과 컴포넌트들을 관리하는 중심 역할을 합니다.
    • AnnotationConfigApplicationContext(비웹) 또는 AnnotationConfigServletWebServerApplicationContext(웹 애플리케이션)의 형태로 컨텍스트를 생성합니다.
  4. 애플리케이션 이벤트 및 리스너 처리:
    • Spring Boot는 애플리케이션의 수명주기 동안 발생하는 여러 이벤트를 처리하기 위해 ApplicationEvent와 ApplicationListener를 사용합니다.
    • 애플리케이션이 시작되기 전에 필요한 이벤트를 발생시키고, 이를 처리하는 리스너들이 동작하여 초기화 작업을 수행하거나, 상태를 로깅하거나, 환경 설정을 변경할 수 있습니다.
    • 예를 들어, ApplicationStartingEvent, ApplicationEnvironmentPreparedEvent, ApplicationPreparedEvent, ApplicationStartedEvent, ApplicationReadyEvent 등이 있습니다.
  5. 환경 설정 준비:
    • SpringApplication.run()은 Spring Environment를 초기화합니다. 이는 application.properties 또는 application.yml 파일로부터 애플리케이션 설정을 로드하고 이를 기반으로 프로파일, 속성 등을 설정합니다.
    • 개발자는 이 환경 설정을 통해 애플리케이션이 실행될 때 필요한 값을 지정하거나, 특정 환경(production, development 등)에 따라 애플리케이션이 다르게 동작하도록 설정할 수 있습니다.
  6. 빈 등록 및 의존성 주입:
    • @ComponentScan을 통해 애플리케이션의 패키지를 스캔하고, 빈으로 등록된 클래스들을 찾아서 Spring 컨텍스트에 등록합니다.
    • 또한 빈 간의 의존성을 자동으로 주입하여, 각 빈이 정상적으로 동작할 수 있도록 설정합니다. 이를 통해 Spring의 DI(의존성 주입) 컨테이너가 동작합니다.
  7. 내장 서버 구동 (웹 애플리케이션):
    • 만약 애플리케이션이 웹 애플리케이션이라면, SpringApplication.run()은 내장된 웹 서버(예: Tomcat, Jetty)를 자동으로 시작합니다.
    • 이를 통해 외부에 별도의 웹 서버를 설치하거나 설정할 필요 없이 애플리케이션이 HTTP 요청을 받을 수 있는 환경을 자동으로 구성합니다.
  8. 명령어 라인 파싱:
    • SpringApplication.run()은 명령어 라인에서 전달된 인자들을 파싱하여 애플리케이션의 실행에 반영합니다.
    • 이는 애플리케이션 실행 시 환경을 동적으로 변경하거나, 설정 파일을 덮어쓸 때 유용합니다.
  9. CommandLineRunner 및 ApplicationRunner 실행:
    • Spring Boot는 CommandLineRunner나 ApplicationRunner 인터페이스를 구현한 빈을 찾아 실행합니다. 이를 통해 애플리케이션이 시작된 후 특정 초기화 작업을 수행할 수 있습니다.
    • 이 두 인터페이스는 애플리케이션의 실행 직후 원하는 코드를 동작시키는 데 사용됩니다.

 

 

SpringApplication.run()의 실행 과정

SpringApplication.run()의 내부 실행 흐름을 단계별로 설명하면 다음과 같습니다:

  1. 애플리케이션 클래스의 기본 설정
    • 애플리케이션 클래스(즉, @SpringBootApplication이 있는 클래스)를 전달받아 SpringApplication 객체를 생성합니다.
     
  2. 애플리케이션 준비 단계
    • run() 메서드는 초기 애플리케이션 환경을 구성하고, 애플리케이션 컨텍스트를 만들 준비를 합니다.
    • ApplicationContextInitializer를 호출하여 초기화 작업을 수행합니다.
  3. 환경 설정 및 프로파일 적용
    • ApplicationEnvironmentPreparedEvent 이벤트를 발생시켜, 환경 설정이 준비되고 프로파일이 적용됩니다.
  4. 빈 스캐닝 및 컨텍스트 초기화
    • 애플리케이션의 빈(Bean)을 스캔하고 등록합니다.
    • @ComponentScan을 통해 애플리케이션의 패키지를 탐색하고, 필요한 빈을 찾아 Spring 컨텍스트에 등록합니다.
  5. 애플리케이션 컨텍스트 준비
    • 컨텍스트가 초기화되면, ApplicationPreparedEvent 이벤트를 발생시켜 준비 과정을 마무리합니다.
  6. 애플리케이션 컨텍스트 리프레시
    • 컨텍스트를 리프레시(refresh)하여 실제 애플리케이션이 실행될 준비가 완료됩니다.
    • 여기서 웹 애플리케이션의 경우 서블릿 컨테이너를 시작합니다(Tomcat, Jetty 등).
  7. 애플리케이션 시작
    • 애플리케이션이 본격적으로 실행됩니다. 이 시점에서 CommandLineRunner나 ApplicationRunner가 실행됩니다.
    • ApplicationStartedEvent가 발생하여 애플리케이션이 시작되었음을 알립니다.
  8. 애플리케이션 준비 완료
    • 마지막으로 ApplicationReadyEvent가 발생하여 애플리케이션이 정상적으로 시작되고 준비되었음을 알립니다.

SpringApplication.run

SpringApplication.run()은 Spring Boot 애플리케이션의 시작점으로, 애플리케이션의 모든 설정 및 실행 과정을 자동화하여 처리합니다. 이 메서드는 애플리케이션의 환경 설정, 빈 등록, 이벤트 처리, 웹 서버 구동 등의 다양한 작업을 수행하여, 개발자가 애플리케이션을 신속하게 실행하고 동작할 수 있도록 도와줍니다.

public ConfigurableApplicationContext run(String... args) {
		long startTime = System.nanoTime();
		DefaultBootstrapContext bootstrapContext = createBootstrapContext();
		ConfigurableApplicationContext context = null;
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting(bootstrapContext, this.mainApplicationClass);
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
			context.setApplicationStartup(this.applicationStartup);
			prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
			}
			listeners.started(context, timeTakenToStartup);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			if (ex instanceof AbandonedRunException) {
				throw ex;
			}
			handleRunFailure(context, ex, listeners);
			throw new IllegalStateException(ex);
		}
		try {
			if (context.isRunning()) {
				Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
				listeners.ready(context, timeTakenToReady);
			}
		}
		catch (Throwable ex) {
			if (ex instanceof AbandonedRunException) {
				throw ex;
			}
			handleRunFailure(context, ex, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

 

SpringApplication.run() 메서드는 Spring Boot 애플리케이션의 시작점으로, 애플리케이션 컨텍스트를 생성하고 초기화하며, 애플리케이션을 실행하는 데 필요한 모든 설정과 구성을 처리합니다. 주어진 코드는 SpringApplication 클래스의 run 메서드로, 이 메서드의 내부 동작을 매우 상세하게 설명하겠습니다.

전체적인 동작 흐름

  1. Start 시간 기록
  2. Bootstrap 컨텍스트 생성
  3. Headless 속성 설정
  4. RunListeners 초기화 및 시작 알림
  5. 애플리케이션 아규먼트 처리
  6. ConfigurableEnvironment 준비
  7. Banner 출력
  8. ApplicationContext 생성
  9. Context 준비
  10. Context 새로 고침
  11. 애플리케이션 시작 후 처리
  12. 시작 정보 로깅
  13. Listener에게 시작 완료 알림
  14. CommandLineRunner 및 ApplicationRunner 실행
  15. 예외 처리
  16. 애플리케이션 준비 완료 알림
  17. Context 반환

각 단계를 상세히 살펴보겠습니다.

1. Start 시간 기록

long startTime = System.nanoTime();
  • 목적: 애플리케이션의 시작 시간을 기록하여, 애플리케이션이 시작하는 데 걸린 시간을 계산하는 데 사용됩니다.

2. Bootstrap 컨텍스트 생성

DefaultBootstrapContext bootstrapContext = createBootstrapContext();
  • 부트스트랩 컨텍스트: Spring Boot의 초기화 과정에서 사용되는 컨텍스트로, 초기 환경 설정 및 필요한 리소스를 제공합니다. 초기 부트스트랩 과정에서 사용되는 임시 컨텍스트입니다.
  • createBootstrapContext(): DefaultBootstrapContext 객체를 생성하여 초기화 단계에서 필요한 리소스를 준비합니다.

3. Headless 속성 설정

configureHeadlessProperty();
  • 헤드리스 모드: GUI 환경 없이 애플리케이션을 실행할 때 사용하는 설정입니다. 헤드리스 모드는 GUI 환경이 없는 서버에서 실행될 때 유용하며, 디스플레이, 키보드, 마우스 등의 하드웨어에 접근하지 않는 환경에서 사용됩니다.
  • configureHeadlessProperty(): 시스템 속성 java.awt.headless를 설정하여, GUI 관련 리소스를 사용하지 않도록 합니다. 이는 서버 환경에서 불필요한 리소스 로딩을 방지합니다.

4. Run Listener 초기화 및 시작 알림

SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
  • 런 리스너: 애플리케이션 실행 과정 중 특정 시점에 호출되는 리스너입니다. 이는 애플리케이션 실행 단계에서 발생하는 여러 이벤트(시작, 환경 설정, 준비 완료 등)에 대한 리스너들을 관리하는 역할을 합니다.
  • getRunListeners(args): 애플리케이션 실행 시 사용할 리스너 목록을 가져옵니다.
  • listeners.starting(): 애플리케이션 시작을 알리는 이벤트를 리스너에게 전달합니다. 이 시점에서 리스너는 초기화 작업을 수행할 수 있습니다.

5. 애플리케이션 아규먼트 처리

ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
  • 애플리케이션 인자: main 메서드에서 전달된 커맨드 아규먼트를 처리합니다.
  • DefaultApplicationArguments: 커맨드 아규먼트를 파싱하여 ApplicationArguments 객체로 변환합니다.

6. Environment 구성 준비

ConfigurableEnvironment environment 
		= prepareEnvironment(listeners, bootstrapContext, applicationArguments);
  • 환경 설정: 애플리케이션의 설정 및 프로파일을 관리하는 Environment 객체를 준비합니다. 이 객체는 애플리케이션의 프로파일, 속성, 시스템 환경 변수 등을 관리합니다.
  • prepareEnvironment(...): 리스너, 부트스트랩 컨텍스트, 애플리케이션 아규먼트를 기반으로 환경 설정을 초기화합니다. 이 과정에서 설정 파일(application.properties 또는 application.yml)과 시스템 속성, 환경 변수가 로드됩니다.

7. 배너 출력

Banner printedBanner = printBanner(environment);
  • 배너: 애플리케이션 시작 시 콘솔에 출력되는 ASCII 아트나 텍스트입니다. 스프링 부트는 애플리케이션이 실행될 때 터미널에 Spring 배너(기본적으로 Spring 로고)를 출력하는, 이는 이 메서드에서 처리됩니다.
  • printBanner(environment): 환경 설정을 기반으로 배너를 출력합니다. 배너는 사용자 정의하거나 기본 배너를 사용할 수 있습니다.

8. Application Context 생성

context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
  • 애플리케이션 컨텍스트: Spring의 핵심으로, 빈(Bean)들을 관리하고 애플리케이션의 구성 요소를 조립합니다. 
  • createApplicationContext(): 적절한 타입의 ApplicationContext (예: AnnotationConfigServletWebServerApplicationContext 또는 AnnotationConfigApplicationContext)를 생성합니다.
  • setApplicationStartup(...): 애플리케이션 시작 정보를 추적할 수 있도록 ApplicationStartup을 설정합니다.

9. Context 초기화 준비

prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
  • 컨텍스트 준비: 애플리케이션 컨텍스트를 설정하고, 필요한 리소스와 빈을 등록합니다.
  • prepareContext(...): 부트스트랩 컨텍스트, 애플리케이션 컨텍스트, 환경 설정, 리스너, 애플리케이션 아규먼트, 배너를 사용하여 컨텍스트를 준비합니다. 이 과정에서 자동 구성, 빈 스캔, 프로퍼티 설정 등이 이루어집니다.

10. Context 새로 고침

refreshContext(context);
  • 컨텍스트 새로 고침: 애플리케이션 컨텍스트를 초기화하여 모든 빈을 로드하고, 의존성을 주입합니다.
  • refreshContext(context): ApplicationContext의 refresh() 메서드를 호출하여 컨텍스트를 초기화합니다. 이 과정에서 모든 빈이 생성되고 초기화됩니다.

11. 애플리케이션 시작 후 처리

afterRefresh(context, applicationArguments);
  • 애플리케이션 시작 후 처리: 컨텍스트가 새로 고침된 후 추가적인 초기화 작업을 수행합니다.
  • afterRefresh(...): 애플리케이션 컨텍스트가 완전히 초기화된 후 필요한 후처리를 수행합니다.

12. 시작 정보 로깅

Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime); 
if (this.logStartupInfo) { 
	new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup); 
}
  • 시작 시간 계산: 애플리케이션이 시작되는 데 걸린 시간을 계산합니다.
  • 시작 정보 로깅: 설정에 따라 애플리케이션 시작 정보를 로그로 출력합니다. 이 정보에는 시작 시간, 애플리케이션 클래스 등이 포함될 수 있습니다.

13. 리스너에게 시작 완료 알림

listeners.started(context, timeTakenToStartup);
  • 리스너 알림: 애플리케이션이 성공적으로 시작되었음을 리스너에게 알립니다.
  • listeners.started(...): ApplicationStartedEvent를 리스너에게 전달하여, 리스너가 애플리케이션 시작 완료 시점에서 추가 작업을 수행할 수 있도록 합니다.

14. CommandLineRunner 및 ApplicationRunner 실행

callRunners(context, applicationArguments);
  • 런너 실행: CommandLineRunner 및 ApplicationRunner 인터페이스를 구현한 빈들을 실행합니다.
  • callRunners(...): 애플리케이션 컨텍스트에서 해당 인터페이스를 구현한 빈들을 찾아 순차적으로 실행합니다. 이를 통해 애플리케이션 시작 시점에 특정 로직을 실행할 수 있습니다.

15. 예외 처리

		catch (Throwable ex) {
			if (ex instanceof AbandonedRunException) {
				throw ex;
			}
			handleRunFailure(context, ex, listeners);
			throw new IllegalStateException(ex);
		}
  • 예외 처리: 애플리케이션 실행 중 발생한 예외를 처리합니다.
  • AbandonedRunException: 특정 예외 타입은 다시 던지고, 다른 예외는 handleRunFailure(...) 메서드를 통해 처리합니다.
  • handleRunFailure(...): 예외 발생 시 리스너에게 실패 이벤트를 전달하고, 추가적인 예외 처리를 수행합니다.
  • IllegalStateException: 예외를 래핑하여 다시 던집니다.

16. 애플리케이션 준비 완료 알림

		try {
			if (context.isRunning()) {
				Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
				listeners.ready(context, timeTakenToReady);
			}
		}
  • 준비 완료 알림: 애플리케이션이 성공적으로 준비되었음을 리스너에게 알립니다.
  • context.isRunning(): 애플리케이션 컨텍스트가 실행 중인지 확인합니다.
  • listeners.ready(...): ApplicationReadyEvent를 리스너에게 전달하여, 리스너가 애플리케이션이 완전히 준비되었음을 알 수 있도록 합니다.
  • 예외 처리: 준비 완료 알림 중 발생한 예외도 동일하게 처리합니다.

17. 컨텍스트 반환

return context;
  • 컨텍스트 반환: 초기화되고 실행된 ApplicationContext를 반환합니다. 이를 통해 애플리케이션 상태를 외부에서 확인하거나 추가 작업을 수행할 수 있습니다.

 

 

'Spring Boot > Spring Boot Auto Configuration' 카테고리의 다른 글

@EnableAutoConfiguration  (0) 2024.10.16
@SpringBootConfiguration  (0) 2024.10.16
@SpringBootApplication  (0) 2024.10.16
Classpath  (0) 2024.10.16
@Import  (0) 2023.05.04