spring

Spring Boot 애플리케이션이 초기화되는 과정

Lee_SJ 2025. 2. 17. 17:07

⚙️ 1️⃣ JVM 내부에서의 초기 작업

  1. 클래스 로딩 (Metaspace)
    • @SpringBootApplication이 붙은 메인 클래스와 참조된 의존 클래스가 Metaspace에 로드됩니다.
    • 클래스 로더가 SpringApplication.run()을 호출할 때 필요한 ApplicationContext, BeanFactory 등도 함께 로딩됩니다.
    • 이 단계에서 ReflectionClassLoader가 작동합니다.
  2. JIT(Just-In-Time) Compiler 준비
    • 성능 최적화를 위해 HotSpot VM이 frequently used 코드(메인 메서드, 스프링 컨테이너 생성 코드)를 네이티브 코드로 변환.

🚀 2️⃣ Spring Boot 애플리케이션 시작

SpringApplication.run() 실행

SpringApplication.run(MyApplication.class, args)가 실행되면 아래 흐름이 진행됩니다.

🌱 Step 1: SpringApplication 생성

  • SpringApplication 객체를 생성하며 SpringApplicationRunListeners를 준비.
  • SpringFactoriesLoader를 통해 application.properties를 기반으로 환경 설정을 읽어들임.
  • ApplicationContextInitializer와 ApplicationListener들을 메모리에 로드.

메모리 변화:

  • Heap: SpringApplication 객체, 설정 파일 데이터(Environment)가 힙 메모리에 올라감.
  • Metaspace: 설정된 클래스의 메타데이터 저장.

🛠️ Step 2: Environment 준비

  • ConfigurableEnvironment를 생성하고 application.properties나 application.yml 파일을 파싱.
  • 활성화된 Profile 정보를 확인하고 설정을 메모리에 로드.
  • System properties, OS environment variables도 함께 준비.

메모리 변화:

  • Heap: Environment 객체 생성 및 프로퍼티 키-값 저장.
  • Thread Stack: 프로퍼티 파싱 작업 중, 호출 메서드들의 Stack Frame 생성/소멸.

🏗️ Step 3: ApplicationContext 생성

  • AnnotationConfigApplicationContext 또는 GenericWebApplicationContext를 생성.
  • BeanDefinition 생성: 설정 파일(클래스)을 분석하여 Bean 정보를 메모리에 등록.

메모리 변화:

  • Heap: ApplicationContext, BeanDefinition 객체가 올라감.
  • Metaspace: @Configuration, @Bean, @Component로 정의된 클래스 메타데이터 유지.

🔍 3️⃣ Component Scan & Bean 등록

🧬 Step 4: @ComponentScan 작동

  • @SpringBootApplication은 **@ComponentScan**을 포함하므로, basePackages 경로에서 **@Component, @Service, @Repository, @Controller**를 찾아 메모리에 등록.

작동 과정:

  1. Reflection을 통해 클래스의 애너테이션 정보를 조회.(애노테이션은 리플렉션과 프록시를 활용하여 런타임시 작동)
  2. BeanDefinition 생성 → BeanFactory에 등록.
  3. 의존성 주입(DI): @Autowired, @Inject, @Resource 등을 처리.

메모리 변화:

  • Heap: Spring Bean 인스턴스 생성.
  • Metaspace: 스캔된 클래스의 메타데이터 유지.

⚙️ 4️⃣ @Configuration과 @Bean 처리

⚙️ Step 5: @Configuration 클래스 처리

  • @Configuration 클래스는 CGLIB을 이용해 프록시 객체로 변환.
  • 내부의 @Bean 메서드를 호출하여 빈을 등록할 때 싱글톤 보장.
@Configuration
public class AppConfig {
    @Bean
    public UserService userService() {
        return new UserService();
    }
}

메모리 변화:

  • Heap: UserService 객체 생성 및 등록.
  • Metaspace: AppConfig 클래스와 CGLIB 프록시 메타정보 유지.

⚙️ 5️⃣ AOP 프록시 생성

🔍 Step 6: AOP 적용

  • @EnableAspectJAutoProxy(SpringBoot 자동 활성화)로 AOP를 위한 프록시 객체 생성.
  • JDK Dynamic Proxy(인터페이스 기반) 또는 CGLIB Proxy(클래스 기반) 사용.

동작 원리:

  1. BeanPostProcessor가 @Aspect를 탐지.
  2. ProxyFactory가 프록시 객체를 생성.
  3. @Around, @Before, @After Advice를 메서드 호출 시 연결.

메모리 변화:

  • Heap: 프록시 객체 생성.
  • Metaspace: Proxy 클래스의 메타정보 저장.

🌐 6️⃣ Web Server 기동 (내장 톰캣)

🛠️ Step 7: 내장 WAS(Tomcat) 실행

  • SpringApplication이 WebApplicationType을 감지하고 내장 톰캣 서버를 구동.
  • DispatcherServlet을 생성하여 HTTP 요청을 처리.
  • HTTP 포트, 컨텍스트 경로 설정을 기반으로 네트워크 포트 바인딩.

메모리 변화:

  • Heap: ServletContext, Request, Response 객체 생성.
  • Kernel Space: socket을 통해 네트워크 포트 바인딩.

🔄 7️⃣ ApplicationContext 초기화 완료

최종 단계

  • ApplicationContext 초기화 이벤트 발행(ApplicationReadyEvent).
  • CommandLineRunner 및 ApplicationRunner 실행.
  • 애플리케이션 준비 완료 → HTTP 요청 대기.

🧠 정리: 메모리상의 주요 변화

단계 메모리 영역 주요 작업
클래스 로딩 Metaspace 클래스 및 메타정보 로드
환경 설정 로드 Heap Environment 객체 생성
Bean 등록 및 DI Heap BeanFactory, BeanDefinition, Bean 인스턴스 생성
AOP 프록시 생성 Heap 프록시 객체 생성 및 메타정보 등록
웹 서버 기동 Heap ServletContext, DispatcherServlet 생성