0. SpringApplication
- SpringApplication 클래스는 Spring application을 편리하게 기동하는 방법을 제공하는 클래스입니다.
- SpringApplication.run 메서드가 main method로부터 호출되어 bootstrapping 작업을 시작합니다.
- startup과 연관된 메시지가 출력됩니다. (INFO 레벨의 로그)
1. Startup Failure
FaliureAnalyzers
- pring Boot 기동중 에러 발생 시 문제 해결을 담당합니다.
- 여러 에러에 대해 다양한 구현체를 가지고 있습니다.
- 에러 메시지를 출력합니다.
ConditionEvaluationReport
- 어떤 자동 설정이 적용되었고 제외되었는지 그리고 그 이유가 무엇인지를 DEBUG 레벨 로그로 출력해주는 객체
- 애플리케이션이 실행되지 않았는데도 FailureAnalyzer에 의해 명확한 에러 메시지를 받지 못한 경우, 시스템 진단용으로 적합합니다.
활성화 방법 | 설정 |
application.properties | debug=true |
JVM 옵션 | --debug 또는 -Ddebug=true |
Gradle 실행 | ./gradlew bootRun --debug |
IDEA에서 실행 | VM 옵션에 --debug 추가 |
2. Lazy Initialization
- 빈이 애플리케이션 시작 시점이 아닌 필요 시점에 초기화되는 기능
항목 | 설명 |
장점 | - 애플리케이션 기동 시간을 줄여줌. - 빈들이 필요할 때만 초기화됨. (HTTP Request로 인한 필요) |
단점 | - 잘못 셋팅된 빈이 지연 초기화되면 문제를 늦게 발견. - 서버 메모리 부족 시 런타임 오류 발생 가능. |
지연 초기화 활성화 방법 | 모든 빈에 적용 - SpringApplicationBuilder#lazyInitialization()을 통한 SpringApplication 생성 - SpringApplication#setLazyInitialization() 호출 - spring.main.lazy-initialization 속성 사용 특정 빈에만 적용 - @Lazy 어노테이션 사용 |
예제) @Lazy
더보기
@Component
@Lazy
public class HeavyComponent {
public HeavyComponent() {
System.out.println("HeavyComponent 초기화");
}
public void work() {
System.out.println("HeavyComponent 작업 수행");
}
}
@Component
public class AppRunner {
private final HeavyComponent heavyComponent;
public AppRunner(@Lazy HeavyComponent heavyComponent) {
this.heavyComponent = heavyComponent;
System.out.println("AppRunner 초기화");
}
@PostConstruct
public void run() {
System.out.println("AppRunner 생성 완료");
heavyComponent.work();
}
}
- 주입 받는 쪽에서도 @Lazy를 넣어줘야 프록시 객체로 주입받음
3. Application Availability
- 관리 플랫폼에서 애플리케이션이 배포될 경우, Spring Application은 플랫폼에게 availability 정보를 제공해야 합니다
- 이를 위해 Spring Boot는 health check endpoint를 제공하는 actuator 모듈을 지원합니다. (spring-boot-starter-actuator)
availability 정보
구분 | 상태 종류 | 의미 | 예시 / 시점 | 주의사항 |
Liveness
|
정상 (CORRECT) |
애플리케이션 내부가 정상 동작 중이거나 에러를 스스로 회복할 수 있는 상태 | ApplicationContext 리프레시 완료 이후 |
외부 시스템 상태에 의존하면 안 됨
|
손상 (BROKEN) |
애플리케이션이 스스로 회복 불가능한 상태 | 내부 오류가 지속되는 경우 |
손상 상태 판단 시 외부 시스템 영향 고려 ❌
|
|
Readiness
|
정상 (ACCEPTING_TRAFFIC) |
애플리케이션이 트래픽을 처리할 준비가 된 상태 | ApplicationRunner 또는 CommandLineRunner 실행 완료 후 |
@PostConstruct는 Readiness와 무관
|
손상 (REFUSING_TRAFFIC) |
애플리케이션이 트래픽을 받을 수 없는 상태 | 기동 중 또는 일부 구성 요소 지연 시 |
초기화 미완료 혹은 종속 리소스 준비 안 됨
|
availability 조회
- ApplicationAvailability를 사용하면 현재 애플리케이션의 Liveness / Readiness 상태를 조회할 수 있습니다.
예제) AvailabilityChecker
더보기
@Component
public class AvailabilityChecker {
private final ApplicationAvailability availability;
public AvailabilityChecker(ApplicationAvailability availability) {
this.availability = availability;
}
public void checkAvailability() {
LivenessState liveness = availability.getLivenessState();
if (liveness == LivenessState.BROKEN) System.out.println("⚠ 애플리케이션이 손상된 상태입니다.");
else if (liveness == LivenessState.CORRECT) System.out.println("✅ 애플리케이션이 정상적으로 초기화되었습니다.");
ReadinessState readiness = availability.getReadinessState();
if (readiness == ReadinessState.REFUSING_TRAFFIC) System.out.println("❌ 트래픽을 받을 준비가 안된 상태입니다.");
else if (readiness == ReadinessState.ACCEPTING_TRAFFIC) System.out.println("✅ 정상적으로 트래픽을 수용할 수 있는 상태입니다.");
}
}
4. Application Events and Listeners
- SpringApplication 클래스는 애플리케이션의 시작 프로세스를 관리합니다
- 이벤트 드리븐 매커니즘으로 초기화 작업을 수행합니다.
- 애플리케이션 기동 시 ApplicationEvent를 발행합니다.
ApplicationEvent
- ApplicationEvent는 Spring Framework의 이벤트 발행 매커니즘을 통해 발행됩니다.
- 발행된 ApplicationEvent는 등록된 Listener들에게 전달됩니다.
종류
이벤트 | 발생 시점 | 리스너 설명 |
ApplicationStartingEvent | SpringApplication.run() 호출 직후 | - LoggingApplicationListener: 초기 로깅 시스템 구성 (color, logback 등) - BackgroundPreinitializer: 공통 클래스/기능 선행 초기화 (비동기) - DelegatingApplicationListener: spring.factories 기반 리스너 위임 |
ApplicationEnvironmentPreparedEvent | 환경 설정 완료 (Environment) | - EnvironmentPostProcessor...: application.yml 등 config 파일 적용 - AnsiOutputApplicationListener: ANSI 로그 컬러 설정 반영 - FileEncoding...: 시스템 인코딩 유효성 체크 (file.encoding) |
ApplicationContextInitializedEvent | ApplicationContext 생성됨 (Bean 등록 전) |
주로 위임 리스너들과 백그라운드 프리로더만 동작 |
ApplicationPreparedEvent | Bean 정의 로드 완료 refresh() 전 (webserver 초기화 전) |
- 설정이 반영된 최종 로깅 환경 구성 - Delegating 리스너가 다음 단계 리스너들 위임 준비 |
WebServerInitializedEvent | 내장 톰캣/웹 서버 포트 바인딩 완료 | - SpringApplicationAdminMXBeanRegistrar: JMX MBean 등록 - ServerPortInfo...: 실제 바인딩된 포트 정보를 환경에 기록 |
ContextRefreshedEvent | 모든 Bean 초기화 완료 | - ConditionEvaluationReport...: @Conditional 평가 결과 로그 출력 - ClearCaches...: 불필요한 캐시 제거 - SharedMetadataReader...: 클래스 스캐닝에 사용하는 Bean 초기화 |
ApplicationStartedEvent | refresh() 이후 Runner 실행 전 |
- StartupTimeMetricsListener: 애플리케이션 시작 시간 측정 및 기록 (Micrometer) - TomcatMetricsBinder: 톰캣 리소스 상태 모니터링 (active thread, connection 등) |
AvailabilityChangeEvent (CORRECT) |
애플리케이션이 "살아있음" | - ApplicationAvailabilityBean: /actuator/health/liveness 엔드포인트에서 사용 - 애플리케이션이 정상 실행 중임을 나타냄 |
ApplicationReadyEvent | ApplicationRunner CommandLineRunner 실행 완료 |
- StartupTimeMetricsListener: 최종 시작 시간 기록 완료 - JMX 등록 리스너가 여기도 있음 |
AvailabilityChangeEvent (ACCEPTING_TRAFFIC) |
애플리케이션이 트래픽 받을 준비 완료 | - /actuator/health/readiness 상태로 트래픽 수신 가능 표시 |
ApplicationFailedEvent | 실행 중 예외 발생 시 | - 실패 시 로그 남기고 상태 전파, 종료 처리 |
전파
- ApplicationContext는 계층 구조를 가짐
- 자식 ApplicationContext에서 ApplicationEvent 발행하면 부모 ApplicationContext에 ApplicationEvent가 전파됩니다.
- Listener는 전달받은 ApplicationEvent가 직접 발행한건지 전파된건지 구분해야 합니다.
- 이를 위해 Listener는 자신이 속한 ApplicationContext의 참조를 가지고 있어야 합니다.
- Listener는 ApplicationContextAware 인터페이스를 구현함으로써 자신의 ApplicationContext 참조 가질 수 있습니다
- Listener가 빈으로 등록되어 있다면 @Autowired로 ApplicationContext를 주입받을 수 있습니다.
ApplicationListener
- ApplicationEvent를 listen 하는데 쓰입니다.
등록 방법
방법 | 설명 |
META-INF/spring.factories에 등록 |
이벤트 리스너 구현체를 spring.factories에 등록하기
|
Environment에 등록 |
org.springframework.context.ApplicationListener를 key로 하여 구현체를 등록합니다.
|
SpringApplication을 통해 등록 |
SpringApplication 클래스에서 직접 ApplicationListener를 등록합니다.
|
예제) ApplicationListener 구현하기
더보기
public class MyEventListener implements ApplicationListener<ApplicationEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
System.out.println("hello event! " + event.getClass().getSimpleName());
}
}
예제) ApplicationListener 등록하기
더보기
1. META-INF/spring.factories에 등록
org.springframework.context.ApplicationListener=\
org.example.event.MyMetaInfListener
2. Environment에 등록
spring:
application:
listeners:
- com.example.listener.MyEnvironmentListener
org.springframework.context.ApplicationListener=\
org.springframework.boot.context.config.DelegatingApplicationListener
3. SpringApplication에 등록
@SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Main.class);
app.addListeners(new MyProgrammaticListener());
app.run(args);
}
}
Web Environment
- SpringApplication은 현재 애플리케이션에 적절한 ApplicationContext 타입인 WebApplicationType을 정해줍니다.
- 내부적으로 classpath에 DispatcherServlet 클래스의 존재 여부에 따라 결정됩니다.
- SpringApplication은 setWebApplicationType()을 호출하여 명시적으로 지정할 수 있습니다.
WebApplicationType | 설명 |
사용되는 ApplicationContext 구현체
|
SERVLET | Spring MVC 기반 웹 애플리케이션 |
AnnotationConfigServletWebServerApplicationContext
|
REACTIVE | Spring WebFlux 기반 웹 애플리케이션 |
AnnotationConfigReactiveWebServerApplicationContext
|
NONE | 웹 환경이 아닌 일반 애플리케이션 (CLI 등) |
AnnotationConfigApplicationContext
|
Accessing Application Arguments
- ApplicationArguments
- SpringApplication.run() 실행 시, 전달된 인자를 파싱해서 제공하는 객체입니다.
- 빈으로 자동 등록되므로 어디서든 주입받아 사용할 수 있습니다.
- CommandLinePropertySource
- Environment에 CommandLinePropertySource를 자동으로 등록합니다.
- 이로 인해 @Value 어노테이션으로 프로퍼티 값을 주입받을 수 있습니다.
Using the ApplicationRunner or CommandLineRunner
항목 | ApplicationRunner |
CommandLineRunner
|
실행 시점 | Spring Boot 애플리케이션 실행 후 빈 초기화가 끝난 직후 | 동일 |
run() 파라미터 | ApplicationArguments args | String... args |
명령행 인자 접근 방식 | 구조화된 형태 (옵션, 값 등 분리 제공) | 단순 문자열 배열 |
명령행 인자 파싱 | args.getOptionNames(), args.getOptionValues() 등 |
수동으로 for문 등을 이용해 직접 파싱
|
주 용도 | 명령행 인자를 키-값 형태로 받아 파싱 필요할 때 |
단순한 인자 전달 및 처리
|
순서 지정 가능 여부 | 가능 (@Order, Ordered 인터페이스 구현) | 동일 |
등록 방법 | @Component 또는 @Bean | 동일 |
예제) CommandLineRunner
더보기
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) {
// Do something...
}
}
참고
'Spring > Spring Boot' 카테고리의 다른 글
[Spring Boot] 2-3. Core Features: Profile (0) | 2023.10.09 |
---|---|
[Spring Boot] 2-2. Core Features: Externalized Configuration (2) | 2023.10.09 |
[Spring Boot] 1-2. Spring Boot 사용하기 (1) | 2023.10.07 |
[Spring Boot] 1-1. Spring Boot 사용하기 (0) | 2023.10.07 |
[Spring Boot][KoLiving] 3-2 Sign-up (0) | 2023.09.19 |