2024. 10. 16. 11:50ㆍSpring Boot/Spring Boot Auto Configuration
SpringApplication.run()은 Spring Boot 애플리케이션의 시작점에서 사용되는 메서드로, Spring Boot 애플리케이션을 실행하고 부트스트랩(초기화)하는 역할을 합니다. 이 메서드는 애플리케이션의 실행을 위한 여러 초기화 작업을 수행하며, Spring 컨텍스트를 생성하고 설정을 적용한 후에 애플리케이션을 실행할 준비를 마칩니다.
아래는 SpringApplication.run()의 동작 과정을 상세하게 설명한 내용입니다.
SpringApplication.run()의 주요 역할
- SpringApplication 객체 생성:
- SpringApplication.run()은 내부적으로 SpringApplication 객체를 생성하고 이를 통해 애플리케이션을 부트스트랩합니다.
- 이 객체는 애플리케이션 실행 중 필요한 환경 설정을 관리하고, 필요한 여러 가지 리스너, 초기화 작업, 애플리케이션 이벤트 등을 처리합니다.
- 애플리케이션 유형 결정:
- SpringApplication은 애플리케이션이 웹 애플리케이션인지 비웹 애플리케이션인지 자동으로 감지합니다.
- Spring Boot는 클래스패스에 서블릿 관련 라이브러리가 있는지 확인한 후, 웹 애플리케이션이면 내장된 톰캣, 제티 등의 서블릿 컨테이너를 설정하고 시작합니다.
- Spring 컨텍스트 생성:
- Spring Boot는 애플리케이션의 ApplicationContext를 생성합니다. 이 컨텍스트는 Spring 프레임워크에서 빈(Bean)을 관리하고, 애플리케이션의 모든 설정과 컴포넌트들을 관리하는 중심 역할을 합니다.
- AnnotationConfigApplicationContext(비웹) 또는 AnnotationConfigServletWebServerApplicationContext(웹 애플리케이션)의 형태로 컨텍스트를 생성합니다.
- 애플리케이션 이벤트 및 리스너 처리:
- Spring Boot는 애플리케이션의 수명주기 동안 발생하는 여러 이벤트를 처리하기 위해 ApplicationEvent와 ApplicationListener를 사용합니다.
- 애플리케이션이 시작되기 전에 필요한 이벤트를 발생시키고, 이를 처리하는 리스너들이 동작하여 초기화 작업을 수행하거나, 상태를 로깅하거나, 환경 설정을 변경할 수 있습니다.
- 예를 들어, ApplicationStartingEvent, ApplicationEnvironmentPreparedEvent, ApplicationPreparedEvent, ApplicationStartedEvent, ApplicationReadyEvent 등이 있습니다.
- 환경 설정 준비:
- SpringApplication.run()은 Spring Environment를 초기화합니다. 이는 application.properties 또는 application.yml 파일로부터 애플리케이션 설정을 로드하고 이를 기반으로 프로파일, 속성 등을 설정합니다.
- 개발자는 이 환경 설정을 통해 애플리케이션이 실행될 때 필요한 값을 지정하거나, 특정 환경(production, development 등)에 따라 애플리케이션이 다르게 동작하도록 설정할 수 있습니다.
- 빈 등록 및 의존성 주입:
- @ComponentScan을 통해 애플리케이션의 패키지를 스캔하고, 빈으로 등록된 클래스들을 찾아서 Spring 컨텍스트에 등록합니다.
- 또한 빈 간의 의존성을 자동으로 주입하여, 각 빈이 정상적으로 동작할 수 있도록 설정합니다. 이를 통해 Spring의 DI(의존성 주입) 컨테이너가 동작합니다.
- 내장 서버 구동 (웹 애플리케이션):
- 만약 애플리케이션이 웹 애플리케이션이라면, SpringApplication.run()은 내장된 웹 서버(예: Tomcat, Jetty)를 자동으로 시작합니다.
- 이를 통해 외부에 별도의 웹 서버를 설치하거나 설정할 필요 없이 애플리케이션이 HTTP 요청을 받을 수 있는 환경을 자동으로 구성합니다.
- 명령어 라인 파싱:
- SpringApplication.run()은 명령어 라인에서 전달된 인자들을 파싱하여 애플리케이션의 실행에 반영합니다.
- 이는 애플리케이션 실행 시 환경을 동적으로 변경하거나, 설정 파일을 덮어쓸 때 유용합니다.
- CommandLineRunner 및 ApplicationRunner 실행:
- Spring Boot는 CommandLineRunner나 ApplicationRunner 인터페이스를 구현한 빈을 찾아 실행합니다. 이를 통해 애플리케이션이 시작된 후 특정 초기화 작업을 수행할 수 있습니다.
- 이 두 인터페이스는 애플리케이션의 실행 직후 원하는 코드를 동작시키는 데 사용됩니다.
SpringApplication.run()의 실행 과정
SpringApplication.run()의 내부 실행 흐름을 단계별로 설명하면 다음과 같습니다:
- 애플리케이션 클래스의 기본 설정
- 애플리케이션 클래스(즉, @SpringBootApplication이 있는 클래스)를 전달받아 SpringApplication 객체를 생성합니다.
- 애플리케이션 준비 단계
- run() 메서드는 초기 애플리케이션 환경을 구성하고, 애플리케이션 컨텍스트를 만들 준비를 합니다.
- ApplicationContextInitializer를 호출하여 초기화 작업을 수행합니다.
- 환경 설정 및 프로파일 적용
- ApplicationEnvironmentPreparedEvent 이벤트를 발생시켜, 환경 설정이 준비되고 프로파일이 적용됩니다.
- 빈 스캐닝 및 컨텍스트 초기화
- 애플리케이션의 빈(Bean)을 스캔하고 등록합니다.
- @ComponentScan을 통해 애플리케이션의 패키지를 탐색하고, 필요한 빈을 찾아 Spring 컨텍스트에 등록합니다.
- 애플리케이션 컨텍스트 준비
- 컨텍스트가 초기화되면, ApplicationPreparedEvent 이벤트를 발생시켜 준비 과정을 마무리합니다.
- 애플리케이션 컨텍스트 리프레시
- 컨텍스트를 리프레시(refresh)하여 실제 애플리케이션이 실행될 준비가 완료됩니다.
- 여기서 웹 애플리케이션의 경우 서블릿 컨테이너를 시작합니다(Tomcat, Jetty 등).
- 애플리케이션 시작
- 애플리케이션이 본격적으로 실행됩니다. 이 시점에서 CommandLineRunner나 ApplicationRunner가 실행됩니다.
- ApplicationStartedEvent가 발생하여 애플리케이션이 시작되었음을 알립니다.
- 애플리케이션 준비 완료
- 마지막으로 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 메서드로, 이 메서드의 내부 동작을 매우 상세하게 설명하겠습니다.
전체적인 동작 흐름
- Start 시간 기록
- Bootstrap 컨텍스트 생성
- Headless 속성 설정
- RunListeners 초기화 및 시작 알림
- 애플리케이션 아규먼트 처리
- ConfigurableEnvironment 준비
- Banner 출력
- ApplicationContext 생성
- Context 준비
- Context 새로 고침
- 애플리케이션 시작 후 처리
- 시작 정보 로깅
- Listener에게 시작 완료 알림
- CommandLineRunner 및 ApplicationRunner 실행
- 예외 처리
- 애플리케이션 준비 완료 알림
- 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 |