스프링부트 정의

0. Spring Boot 이전

Spring Boot이전의 Sprin이 등장하기도 전에는 EJB(Enterprise JavaBeans)가 업무 로직을 담당하는 자바 표준 기술이었다. EJB로 개발자들은 비즈니스 로직을 중점적으로 다룰 수 있었으나 하나의 기능을 구현하기 위해 클래스간 상송, 인터페이스의 구현 등 각 클래스간 의존도가 매우 높은 상황이었다. 이외에도 J2EE와 같은 자바 플랫폼이 존재했다.

Spring은 이러한 복잡성과 제약사항을 줄이고 개발자들에게 더 단순하고 유연한 개발 방식을 제공하기 위해 등장했다. Spring의 핵심 원칙은 의존성 주입으로 코드의 결합도를 낮추고 유닛별 테스트를 용이하게 만들었다.

하지만 이러한 Spring은 XML 기반의 설정이 주를 이루오 복잡하였고 초기 설정과 부트스트랩에 많은 시간과 노력이 필요했고 다양한 라이브러리들이 등장하면서 모듈관의 호환성 문제로 인한 의존성 관리 문제등이 발생했다.

🕯️부트스트랩?

  • 웹사이트를 쉽게 만들수 있도록 도와주는 HTML, CSS, JS 프레임워크
  • 코딩의 양을 줄여준다는 가장 큰 장점



1. Spring Boot의 등장

위에서 살펴봤던 여러 이유들로 인해 Spring Boot가 등장했다. Spring Boots는 실행만 하면 Spring 기반의 상용화가 가능한 애플리케이션을 쉽게 만들기 위해 단독 실행을 가능하게 해주는 Spring 프로젝트이다. "관습 위의 설정"이라는 철학에 따라 복잡한 설정 없이도 애플리케이션을 빠르게 실행할 수 있게 설정되었다.

[Spring Boot의 차별화된 장점들]
1. 내장 서버 : Tomcat, Jetty, Undertow와 같은 웹 서버를 내장하고 있어 별도의 웹 서버 설치 및 설정 없이 애플리케이션을 실행할 수 있다.
2. 자동 구성(Auto Configuration) : Spring Boot는 프로젝트의 의존성을 기반으로 자동으로 구성을 해준다. 예를 들어, spring-boot-starter-web 의존성이 포함되면 웹 애플리케이션으로 구성해준다.
3. 스타터 의존성(Starter Dependencies) : 기능별로 묶여있는 의존성 패키지로 개발자는 필요한 기능의 스타터만 추가하면 관련된 모든 의존성이 자동으로 포함된다.
4. 액추에이터(Actuator): 애플리케이션의 운영 정보를 제공하는 모듈로, 메트릭, 상태 체크, 환경 정보 등 다양한 엔드포인트를 제공한다.



2. Spring Boot역사

해당 부분은 코딩을 하면서 변경사항을 찾게 되면 지속적으로 업데이트 할 예정이다.

Spring Boot 1.0 : 2014년에 출시, 자동 구성 기능 제공, 내장서버지원, 스타터를 통한 의존성 관리

Spring Boot 1.5 : 2017년 초기 출시, Actuator 기능 추가

Spring Boot 2.0 : 2018년에 출시, Spring 5.0 지원, 반응형 웹 프로그래밍 지원

Spring Boot 2.1 : Java 11 지원

Spring Boot 2.2 : Java 13 지원, 프로퍼티 마이그레이션 지원

Spring Boot 2.3 : Docker와의 통합 개선

Spring Boot 2.4 : Java 15 지원, 애플리케이션 설정파일 yml 혹은 properties에 여러 프로파일 동시에 정의 가능

Spring Boot 2.5 : Spring Data JPA에서 getOne을 대체하는 새로운 getById 메서드를 도입

Spring Boot 2.6 : Apache Kafka 3.0으로 업그레이드, Java Runtime 정보를 노출

Spring Boot 2.7 : WebSecurityConfigurerAdapter에서 SecurityFilterChain으로 마이그레이션

Spring Boot 3.0 : Java 17 지원, Java EE를 jakarta EE로 대체 (javax. 에서 jakarta. 로 변경), RFC 7807스펙 지원

🕯️ 마이그레이션이란?
환경, 플랫폼, 버전, 시스템 또는 기술로부터 다른 환경, 플랫폼, 버전, 시스템 또는 기술로 옮기는 프로세스를 의미한다.
IT 분야에서 이 용어는 주로 데이터베이스의 데이터를 다른 데이터베이스로 이전하거나, 소프트웨어의 한 버전에서 다음 버전으로 업그레이드하는 등의 작업에 사용한다.

🕯️ RFC 란?
RFC는 "Request for Comments"의 약자로, 인터넷 관련 기술과 프로토콜, 작동 원칙, 그 외 다양한 컴퓨터 네트워킹에 관한 사항들을 기술한 문서들의 시리즈를 의미

참고로 Spring Boot 3.0 에서 Java17은 사실상 필수이다.



3. Spring Boot 동작 원리

1. 애플리케이션 실행
애플리케이션 시작 지점은 @SpringBootApplication 어노테이션이 붙은 메인클래스에서 SpringApplication.run()이다. 해당 메소드가 스프링 애플리케이션의 시작점이다.


2. 이벤트 리스너 등록
SpringApplication이 실행되면서 각 단계마다 관련된 이벤트가 발생 ->
해당 이벤트를 구독하는 리스너가 있다면, 리스너의 onApplicationEvent 메서드가 호출되어 이벤트를 처리

🕯️Spring boot 의 이벤트 리스터

  • 스프링 부트는 여러 가지 기본 이벤트 리스너를 제공한다. 예를 들면 ApplicationStartingEvent, ApplicationEnvironmentPreparedEvent, ApplicationPreparedEvent, ApplicationReadyEvent 등의 이벤트가 있다.
  • 이벤트들은 애플리케이션의 시작부터 준비, 실행에 이르는 다양한 시점에서 발생한다.
  • SpringApplication 클래스의 addListeners 메서드를 사용하여 직접 이벤트 리스너를 등록할 수 있다.




3. 환경준비
애플리케이션을 실행하는데 필요한 환경변수, 프로파일, 프로퍼터드으이 설정정보를 로드하고 준비하는 단계이다. Environment객체는 환경속성에 대한 접근을 제공하며 여기에는 JVM 시스템 프로퍼터, 시스템 환경변수, 구성파일의 프로퍼티(application.properties, application.yml) 등이 포함된다.
환경이 준비되면 ApplicationEnvironmentPreparedEvent가 발생하고 이 시점에서 개발자는 프로그래밍 방식으로 환경 속성을 변경하거나 다른 설정 작업을 수행할 수 있다.

🕯️프로파일, 프로퍼티

  • 프로파일은 특정한 환경(개발, 테스트, 운영 등)에 따라 애플리케이션 구성을 다르기 적용할 수 있게 해준다, @Profile 어노테이션을 사용하여 특정 빈이 어떤 프로파일에서만 등록되도록 할 수 있다.
  • 프로퍼티는 application.properties 또는 application.yml 파일을 기본적으로 로드한다, 이 파일들은 src/main/resources 디렉토리 아래에 위치한다, 프로퍼티 값들 사이에는 우선순위가 있다.




4. ApplicationContext 생성
ApplicationContext는 빈의 설정, 생성, 관리 등의 작업을 처리하는데 중심적인 역할을 한다. ApplicationContext는 빈 팩토리 (BeanFactory)의 확장이며 애플리케이션 런타임 환경에 대한 정보에 액세스하는 기능을 추가적으로 제공한다.
스프링 부트는 애플리케이션의 유형(웹 애플리케이션, 배치 애플리케이션, 리액티브 애플리케이션 등)에 따라 적절한 ApplicationContext 유형을 선택합한다. 웹 애플리케이션의 경우 AnnotationConfigServletWebServerApplicationContext 같은 웹 전용 컨텍스트가 선택된다.
선택된 ApplicationContext 인스턴스가 생성되고 초기화되며 이 과정에서 애플리케이션의 설정정보, 프로퍼티, 프로파일 등이 해당 컨텍스트에 로드된다.
ApplicationContext는 @Component, @Service, @Repository, @Controller 등의 어노테이션을 포함하는 클래스들을 스캔하여 빈 정의를 로드한다.
또한, @Configuration 클래스들 또한 스캔되어 해당 설정 정보가 컨텍스트에 로드된다.
의 생명주기 관리는 ApplicationContext에 의해 수행됩니다. 이에는 빈의 생성, 초기화, 소멸 등의 과정이 포함된다.

요약하면 ApplicationContext는 스프링 애플리케이션의 중심적인 부분으로 빈의 관리 및 다양한 기능을 제공하며 스프링 부트는 애플리케이션의 유형과 설정에 따라 적절한 ApplicationContext를 초기화하고 준비한다.




5. ApplicationPreparedEvent 발생
ApplicationPreparedEvent를 활용하면 빈들이 실제로 로드되기 전에 특정 작업을 수행할 수 있다. 예를 들어 리소스의 초기 검증, 특정 설정의 확인, 로그의 초기 설정 등의 작업을 이 시점에서 수행할 수 있다.
ApplicationPreparedEvent는 스프링 부트 애플리케이션 초기화 과정 중 ApplicationContext가 준비된 상태에서, 그리고 빈들이 로드되기 전에 발생하는 이벤트이다.
개발자는 이 이벤트를 감지하기 위해 리스너 등록이 가능하다.
예시코드는 다음과 같다.

@Component
public class MyPreparedEventListener implements ApplicationListener<ApplicationPreparedEvent> {

    @Override
    public void onApplicationEvent(ApplicationPreparedEvent event) {
        // 이벤트 발생 시 실행될 로직
        System.out.println("ApplicationPreparedEvent가 발생");
    }
}




6. BeanFactory 설정

🕯️BeanFactory

  • BeanFactory는 스프링 컨테이너의 가장 기본적인 형태로 스프링 빈의 생성과 관리를 담당하는 인터페이스이다, 빈의 생명주기와 설정을 처리한다
  • 대부분의 스프링 애플리케이션은 BeanFactory를 직접 사용하기 보단 ApplicationContext를 사용한다.
  • 즉 ApplicationContext는 BeanFactory의 확장된 형태

스프링 쿠트는 개발의 편의성을 위해 다양한 자동 설정을 제공하는데 클래스패스에 Spring Web MVC 관련 라이브러리가 있으면 웹 MVC 관련 빈들을 자동으로 설정하고, 데이터베이스 관련 라이브러리가 있으면 데이터베이스 연결 등을 설정한다.

이러한 자동 설정은 @EnableAutoConfiguration 어노테이션을 통해 활성화되며 @SpringBootApplication어노테이션에 해당 어노테이션이 포함되어있다.

자동 설정은 spring.factories 파일 내에 정의되어 있으며 이 파일은 스프링 부트 자동 설정 JAR 내부에 위치해있다.

즉, SpringApplication은 시작 시 spring.factories 파일을 읽어 들이며 이 파일은 스프링 부트 자동 설정 JAR의 META-INF 디렉토리에 포함되어 있다. spring.factories 파일 내의 EnableAutoConfiguration 키에 연결된 클래스들은 스프링 부트의 자동 설정 클래스들로 간주된다. 이 클래스들은 특정 라이브러리가 클래스패스에 있을 때 자동으로 설정을 적용하는 역할을 한다.

각 자동 설정 클래스는 특정 조건 하에서만 적용되는데 이 조건은 @Conditional 어노테이션과 그의 확장된 형태들로 정의된다. 예를 들 @ConditionalOnClass는 특정 클래스가 클래스패스에 존재할 때만 설정이 활성화된다.

조건에 부합하는 자동 설정 클래스들은 그 안에 정의된 빈 정의를 BeanFactory (정확히는 ApplicationContext 내의 BeanFactory)에 등록하게 된다.. 이렇게 등록된 빈 정의는 나중에 애플리케이션 실행 중에 인스턴스화되어 실제 객체로 생성된다.

정리하자면 BeanFactory는 스프링 부트 애플리케이션에서 필요한 빈들의 정의를 받아 저장하게 되고 이후 애플리케이션의 라이프사이클 동안 이 빈들은 필요에 따라 생성되거나 다른 빈들과의 관계가 주입되며 애플리케이션의 다양한 로직을 수행하는 데 사용된다.




7. 빈 등록 및 로드
스프링 부트 애플리케이션은 기본적으로 시작 클래스가 위치한 패키지를 기준으로 컴포넌트 스캔을 시작한다. @Component, @Service, @Repository, @Controller, @RestController 등의 어노테이션이 붙은 클래스들을 찾아서 빈으로 등록한다.

🕯️@ComponentScan
스프링 부트의 경우 별도로 @ComponentScan을 지정하지 않아도 메인 애플리케이션 클래스(즉 @SpringBootApplication 어노테이션이 붙은 클래스)가 위치한 패키지를 기준으로 자동으로 컴포넌트 스캔이 이루어잔다. 이는 @SpringBootApplication 어노테이션 안에 @ComponentScan이 포함되어 있기 때문이다.

@Configuration 어노테이션이 붙은 클래스는 설정 클래스로 간주됩니다. 이런 설정 클래스 내에서 @Bean 어노테이션이 붙은 메서드는 해당 메서드가 반환하는 객체를 빈으로 등록한다.

빈이 등록되면, @Autowired나 생성자 주입 등의 방식을 통해 해당 빈에 필요한 의존성이 주입된다.

모든 의존성이 주입된 후, 빈의 초기화 메서드가 호출된다.이후 해당 빈은 애플리케이션의 라이프사이클 동안 사용된다.




8. ApplicationReadyEvent 발생
애플리케이션 컨텍스트가 모든 빈을 로드하고 초기화한 후, 애플리케이션이 요청을 받아 처리할 준비가 완료된 시점에 발생한다. 웹 애플리케이션의 경우, 내장 웹 서버도 이 시점에 완전히 시작된다고 볼 수 있다.

즉 ApplicationReadyEvent는 애플리케이션의 시작 후 초기화나 다른 특정 작업을 수행하기 위한 훅(hook) 역할을 한다 .




9. 서버 실행 (웹 애플리케이션인 경우)
스프링 부트는 내장 웹 서버를 구동하여 웹 애플리케이션을 실행한다. 기본적으로 Tomcat를 기본 웹 서버로 사용하며 이 외에 Jety, Undertow 서버로 변경 가능한다.

선택된 웹 서버는 초기화되고 웹 애플리케이션의 컨텍스트에 맞게 설정된다.

기본적으로 내장 웹 서버는 8080포트에서 실행되며 웹 서버가 구동되고 웹 요청을 받을 준비가 된다.

서버가 시작되면 HTTP요청을 받아 해당 요청을 처리하는 적절한 컨트롤러나 엔트포인트로 라우팅한다.