[SpringBoot] 1. SpringBoot
객체지향 프로그래밍 (OOP) : 프로그램을 일련의 독립된 객체들로 이해하는 프로그래밍 방법론
- 캡슐화 (
Encapsulation) : 변수와 함수를 하나의 단위로 묶는 것 - 정보 은닉 (
Information Hiding) : 프로그램의 구현을 외부로 드러나지 않게 내부로 감추는 것 - 상속 (
Inheritance) : 자식 클래스가 부모 클래스의 특성과 기능을 그대로 물려받는 것 - 다형성 (
Polymorphism) : 하나의 변수, 또는 함수가 상황에 따라 다른 의미로 해석되는 것
객체지향 5원칙 (SOLID) : 객체자향을 올바르게 설계할 수 있도록 도와주는 원칙
SRP(Single Responsibility Principle) : 객체는 오직 하나의 책임을 가져야 한다.- 클래스를 설계할 때 어플리케이션의 경계를 정하고, 추상화로 어플리케이션 내의 속성과 메소드를 설계해야 한다.
OCP(Open Closed Principle) : 객체는 확장에 대해 개방적이고 수정에 대해 폐쇄적이어야 한다.- 클래스, 모듈, 함수와 연동할 때는 상위 클래스나 인터페이스를 중간에 두어 직접적인 연동을 피해야 한다.
LSP(Liskov Substitution Principle) : 자식 클래스는 항상 자신의 부모 클래스를 대체할 수 있다.- 자식 클래스의 인스턴스는 부모 클래스의 인스턴스 역할을 대신할 때에도 논리적으로 문제가 없어야 한다.
ISP(Interface Segregation Principle) : 클라이언트에서 사용하지 않는 메서드는 사용해선 안 된다.- 각 상황에 맞는 메소드만 클래스에게 제공하도록 인터페이스를 작게 나누어 설계해야 한다.
DIP(Dependency Inversion Principle) : 자신보다 변하기 쉬운 것에 의존해선 안된다.- 추상성이 높고 고수준의 클래스는 구체적이고 저수준의 클래스에 의존하지 않도록 설계해야 한다.
자바 빈 (Java Bean) : 자바 객체를 재사용 가능하도록 컴포넌트화한 클래스
- 클래스는 반드시 패키지화되어야 한다.
- 멤버변수는 프로퍼티 (
Property) 라고 부른다. - 프로퍼티의 접근 제어자는
private이다. - 데이터를 저장하는 필드와 그 데이터를 조작하기 위한 외부에서의 접근은
getter와setter메소드로 한다. - 프로퍼티가
boolean이면,get가 아닌is를 사용해도 된다.
public class MemberInfo {
private int id;
private String Name;
private String pw;
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return Name; }
public void setName(String name) { this.Name = name; }
public String getPw() { return pw; }
public void setPw(String pw) { this.pw = pw; }
}
… 서버 사이드에서 어플리케이선을 개발할 때 자바 빈만으로 해결하지 못하는 문제가 발생한다.
- 기존 어플리케이션에 필요한 비즈니스 로직만이 아닌,
DB와 트랜젝션 처리를 위한 프로그램이 추가로 필요하다.- 각각의 어플리케이션 서버에는 독자적인
API이 제공되기에 어플리케이션의 컴포넌트화가 어렵다.
EJB, J2EE : 비즈니스 로직과 시스템 서비스 로직을 분산하고, 로직 간의 규약을 규정
- 비즈니스 로직을 탑재한 부품을
Enterprise Bean이라 부른다. DB와 트랙젝션 처리 등의 시스템 서비스를 이용하는 부품을 컨테이너 (Container)라 부른다.- 비즈니스 객체들을 관리하는
EJB컨테이너에서 필요할 때마다 객체를 꺼내는 방식으로 객체들 간의 의존성을 해결한다.
@Stateless
public class Service {
@PersistenceContext
private Manager Manager;
public void addCustomer(Customer customer) {
Manager.persist(customer);
}
}
…
EJB는 비즈니스 로직이 특정EJB컨테이너에 종속되는 문제가 발생한다. (→ 기술 침투)
EJB컨테이너를 사용하기 위한 코드 (상속 & 구현)들이 많고,EJB컨테이너가 없으면 불필요한 코드가 된다.- 회사마다
EJB컨테이너를 구현한 내용이 달라 다른 회사의EJB컨테이너로의 변경이 어렵다.→ 회사마다 다르고 복잡한 자바 엔터프라이즈 어플리케이션의 개발을 하나로 단순화하자!
스프링 (Spring) : 자바 (JAVA) 기반의 웹 프레임워크 (Web Framework)
- 순수 자바 객체 (
Plain Old Java Object) 방식 :POLO- 인터페이스를 직접 구현하거나 상속받지 않아 기존 라이브러리 지원에 용이하고, 코드가 간결하며 객체가 가벼움
- 관점지향 프로그래밍 (
Aspect Oriented Programming) :AOP- 로깅, 트랜잭션, 보안 등 여러 모듈에서 공통적으로 사용하는 기능을 분리하여 관리할 수 있음
- 의존성 주입 (
Dependency Injection) :DI- 프로그래밍 구성 요소 간 의존 관계를 코드 밖에서 설정을 통해 정의해, 재사용률을 높이고 모듈 간 결합도를 낮춤
- 제어의 역전 (
Inversion of Control) :IoC- 객체의 생성부터 소멸까지의 제어권이 프레임워크에게 있어, 외부 라이브러리 코드가 개발자의 코드를 호출
- 모델-뷰-컨트롤러 (
Model-View-Controller) :MVC패턴- 사용자 인터페이스, 데이터 및 논리 제어의 구현에 사용되는 소프트웨어 디자인 패턴
- 모듈화 디자인 (
Modulation) : 한 프레임워크을 여러 기능적 구성요소 (Module)로 조합해 완성Core: 제어의 역전 (IOC)과 의존성 주입 (DI) 기능 제공DAO: 자바 데이터베이스 커넥터 (JDBC) 추상 계층 제공 (VO클래스로 접근)ORM:ORM이나 데이터베이스API와의 통합 기능 제공Web: 웹 어플리케이션 구현과 관련된 기능 제공JEE: 엔터프라이즈J2EE스펙과 관한 기능 제공
… 스프링 프레임워크가 나왔지만 여전히 개발자가 신경써야 할 일이 많다.
- 서블릿 (
Servlet)에 대한 이해와 서블릿의 배포를 위해 필요한web.xml에 대한 이해- 어플리케이션 컴포넌트를 패키징한
WAR,EAR디렉터리 구조에 대한 지식- 도메인, 포트, 스레드, 데이터 소스 등 어플리케이션을 배포할 때에 필요한 서버 지식
- 복잡한 클래스 로딩 전략, 어플리케이션 모니터링, 유지 관리, 로깅 처리
→ 어플리케이션에 비즈니스 로직을 작성하고, 실행 가능한 파일로 만들어 커맨드라인으로 바로 실행하자!
스프링부트 (SpringBoot) : 스프링 프레임워크 기술을 편리하게 사용할 수 있도록 지원
- 빠른 구동 (
Quick Run) : 어플리케이션에 필요한 의존 관계만 명시하면, 어플리케이션을 빠르게 실행할 수 있음- 스프링
MVC의존 관계를 추가하고 메이븐 혹은 그레이들 프로젝트 설정 - 스프링
MVC의DispatcherServlet의 설정 - 어플리케이션 컴포넌트를
WAR파일로 패키징 WAR파일을 아파치 톰캣 (Apache Tomcat) 같은 서블릿 컨테이너에 배포
- 스프링
- 자동 구성 (
Auto Configuration) : 어플리케이션에 필요한 최소한의 컴포넌트를 대신해서 설정- 클래스패스에 있는
JAR파일이나 여러 설정 파일에 지정된 프로퍼티 정보를 바탕으로 구성 XML파일을 자체적으로 빌드하여 스프링 프로젝트 내 객체 의존성 관리를 자동화- 스프링 외부에 존재하는 라이브러리 또한 가져와 자동으로 구성
- 클래스패스에 있는
- 미리 정의된 방식 (
Opinionated) : 어플리케이션 실행에 필요한 컴포넌트들을starter의존 관계를 기준으로 구성spring-boot-starter-web만 추가하면, 웹 어플리케이션 개발에 필요한 의존 관계를 클래스패스에 모두 넣어줌
- 독립 실행형 (
Standalone) : 어플리케이션에 웹 서버를 내장하여 독립적으로 실행 가능- 실행 가능한
JAR파일로 패키징 →java -jar명령어로 실행 가능 - 어플리케이션이 쉽게 컨테이너화될 수 있어 클라우드 네이티브 (
Cloud Native)에도 적합
- 실행 가능한
- 실제 서비스 환경에 사용 가능 (
Production-Ready)- 헬스 체크 (
Health Check)나 스레드 덤프 (Thread) 분석을 통한 어플리케이션 모니터링 기능 제공 - 매트릭 (
Metric), 상태 확인, 외부 구성과 같은 프로덕션 준비 기능 제공
- 헬스 체크 (
스프링부트 컴포넌트 (SpringBoot Components) : 어플리케이션 개발의 특정 영역에 특화된 요소
spring-boot: 스프링부트의 기본 컴포넌트로서, 다른 컴포넌트를 사용할 수 있도록 지원- 톰캣 (
Tomcat)과 같은 내장 웝 서버 기능 - 데이터베이스 연결 정보와 같은 어플리케이션 설정 정보를 외부화하는 기능
- 톰캣 (
spring-boot-autoconfigure: 어플리케이션에 필요한 의존 관계의 자동 구성을 담당- 클래스패스와 설정 파일의 포로퍼티에 저장된 의존 관계를 바탕으로 스프링 빈 (
Spring Boot)을 추론해 생성
- 클래스패스와 설정 파일의 포로퍼티에 저장된 의존 관계를 바탕으로 스프링 빈 (
spring-boot-starters: 개발의 편의를 위해 제공하는 미리 패키징된 의존 관셰 기술서의 모음spring-boot-CLI: 그루브 코드를 컴파일하고 실행할 수 있는, 관리자 친화적 명령행 도구- 어플리케이션에 수정 사항이 발생할 때마다 파일 내용의 변경 감지
- 의존 관계 관리나 빌드 관련 문제에 대한 걱정 없이 프로트타입 어플리케이션을 빠르게 만들 수 있게 해줌
spring-boot-actuator: 어플리케이션을 모니터링하고 검사 가능한 엑추에이터 엔드포인트 제공JMX나HTTP엔드포인트로 관리할 수 있음- 어플리케이션의 여러 측면의 상태를 감지할 수 있도록 미리 정의된 형태의 다양한 엑추에이터 엔드포인드들을 제공
- 커스텀 엑추에이터 엔드포인트를 추가하거나, 엑추에이터 엔드포인트의 활성화 여부를 설정할 수 있음
- 인가되지 않은 접근으로부터 엔드포인트를 보호할 수도 있음
spring-boot-actuator-autoconfigure: 클래스패스에 있는 클래스를 기반으로 엑추에이터 엔드포인트를 자동 구성- 의존 관계가 클래스패스에 있으면, 이에 해당되는 것을 엑추에이터 엔드포인트로 추가
spring-boot-test: 테스트 케이스의 작성에 필요한 에너테이션 (annotation) 및 메소드 포함spring-boot-test-autoconfigure: 어플리케이션의 테스트 케이스에 필요한 의존 관계를 자동 구성spring-boot-loader: 어플리케이션을JAR파일로 패키징하기 위해 필요한 모든 의존 관계와 내장 웹 서버를 포함- 독립적으로 사용되지 않고 메이븐이나 그레이들 플러그인과 함께 사용
spring-boot-devtools: 어플리케이션 개발을 돕는 여러 개발자 도구들
스프링부트 프로젝트 구조 : 스프링 이니셜라이저 (Spring Initializr)로 자동 생성
pom.xml / build.gradle: 스프링 이니셜라이저에서 스프링부트 프로젝트를 생성할 때 지정한 의존 관계가 들어 있음- 메이븐 (
Maven) 혹은 그레이들 (Gradle)과 같은 빌드 도구를 통해 빌드 가능
- 메이븐 (
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent> <!-- spring-boot-starter-parent : 스타터 의존 관계나 플러그인에 대한 기본 설정 제공 및 관리 -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.1</version>
<relativePath/> <!-- 메이븐 리포지토리에서 parent를 가져옴 -->
</parent>
<groupId>pocj8ur4in</groupId> <!-- 프로젝트 아티펙트 정보 -->
<artifactId>test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>pocj8ur4inTest</name>
<description>pocj8ur4inTest</description>
<properties>
<java.version>21</java.version>
</properties>
<dependencies> <!-- dependencies : 스타터 의존 관계들을 선언 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency> <!-- JUnit, Mockito 등으올 스프링부트 어플리케이션 테스트를 지원 -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins> <!-- plugins : 플러그인들을 선언 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
빌드 플러그인을 통한 스프링부트 어플리케이션의 실행 흐름
resource-plugin의 호출 :src/main/java의 소스 파일들을 빌드 결과가 저장될 디렉터리에 복사compiler-plugin의 호출 : 어플리케이션을 시작하기 전에 소스 코드를 컴파일→ 빌드 플러그인은 저수준의 세부 작업을 모두 추상화하여 개발자가 쉽게 사용할 수 있게끔 해줌
- 래퍼 (
wrapper) 파일 : 빌드 도구를 로컬에 설치하지 않고 프로젝트를 빌드할 수 있게 해줌 - 패키지 (
Packages) 구조 : 자바 클래스를 포함하는 소스 패키지와 테스트 클래스를 포함하는 테스트 패키지로 분리 application.properties파일이 존재하는 리소스 (resource) 폴더 : 프로젝트를 진행하면서 사용할 파일들
스프링부트 메인 클래스 (Main Class) : 패키지 내에서 어플리케이션 실행을 담당
package pocj8ur4in.vocawik;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class VocawikApplication {
public static void main(String[] args) {
SpringApplication.run(VocawikApplication.class, args);
}
}
main()메소드 : 웹 어플리케이션을 실행하는 메소드- 어플리케이션 컴포넌트를 빌드 및 패키징한
WAR / EAR파일을 만들어 웹 서버에 배포할 필요가 없음 - 전통적인 자바 어플리케이션을 실행하는 것처럼 웹 어플리케이션을 실행할 수 있음
- 별도의 서블릿 컨테이너를 실행하지 않고, 스프링부트 어플리케이션이 내장된 서블릿 컨테이너 안에서 실행됨
spring-boot-starter-web이spring-boot-starter-tomcat모듈에 대한 의존 관계를 포함
- 어플리케이션 컴포넌트를 빌드 및 패키징한
@SpringBootApplication어노테이션 : 루트 패키지부터 스프링 어노테이션이 붙은 컴포넌트를 탐색해 관리@EnableAutoConfiguration: 어플리케이션 클래스패스의JAR파일을 바탕으로 어플리케이션을 자동 구성@ComponentScan: 어플리케이션에 존재하는 스프링 컴포넌트를 탐색@Component,@Bean등이 붙은 자바 빈을 스프링에서 관리하기 위해 루트에서부터 탐색@ComponentScan(basePackage = {})로 탐색 범위를 직접 지정할 수 있음 -@SpringBootConfiguration: 스프링부트 어플리케이션 설정을 담당
@Configuration를 내부적으로 포함하여, 컴포넌트 탐색을 통해 어플리케이션 설정 과정에 참여
SpringApplication()클래스 :run()정적 메소드를 통해 스프링부트 어플리케이션을 편리하게 실행
run()메소드가 실행될 때 수행하는 적업의 흐름
- 클래스패스에 있는 라이브러리를 기준으로
SpringApplication클래스의 인스턴스 생성CommandLinePropertySource를 등록해서 명령행 인자를 스프링 프로퍼티로 읽음- 1단계에서 생성한
ApplicationContext를 통해 싱글톤 빈 로딩- 어플리케이션에 설정된
ApplicationRunner와CommandRunner실행
SpringApplication클래스는 클래스패스에 있는JAR의 의존 관계를 바탕으로ApplicationContext인스턴스 생성ApplicationContext는 빈을 생성할 때 필요한 의존 관계 주입을 실행할 스프링IoC컨테이너의 역할을 담당- 클래스패스에 있는 클래스로 어플리케이션 타입이 서블릿 (
Servlet) 혹은 리액티브 (Reactive)인지 유추
스프링부트가
ApplicationContext를 로딩할 때의 전략
- 서블릿 기반 :
AnnotationConfigServletWebSErverApplicationContext클래스 인스턴스 생성- 리액티브 기반 :
AnnotationConfigReactiveWebServletApplicationContext클래스 인스턴스 생성- 둘다 아닐 경우 :
AnnotationConfigApplicationContext클래스 인스턴스 생성
- 필요한 경우에
SpringApplication클래스의 인스턴스를 직접 생성해 어플리케이션 시동 모드를 변경 가능 - 스프링 프로파일 지정, 어플리케이션 리소스 리소스 로더 지정과 같은 기능을
Setter메소드로 제공
application.properties 또는 application.yml : 어플리케이션의 설정 정보 관리
src/main/resources/디렉토리에 자동으로 생성 (기본값은.properties)- 서버 접속 정보, 데이터베이스 접속 정보와 같은 어플리케이션 설정 정보를 소스 코드에서 분리해서 외부화
- 멀티 모듈을 구성하거나 배포 환경가 다중화된 경우에, 파일을 여러 개로 나누어 설정을 다르게 관리할 수 있음
JAR 파일 : 스프링부트 프로젝트로부터 생성된 실행 가능한 파일
- 설정한 패키징 방식에 따라 프로젝트의
target디렉터리에.JAR파일 생성- 메이븐은
spring-boot-maven-plugin플러그인의repackage골 (goal)이 메이븐package라이프사이클과 연동되어, 컴파일된 클래스 파일 (.class)를 리패키징 - 그레이들은 스프링부트 프로젝트를 빌드할 때
org.springframework.boot플러그인이 생성한bootJar테스크가 그레이들build라이프사이클에 편입되어 패키징
- 메이븐은
java -jar명령의 인자로 지정하면 어플리케이션을 실행할 수 있음ctrl+c등을 통해 자바 프로세스를 종료하면, 스프링부트 어플리케이션 또한 종료
META-INF: 실행할JAR파일의 핵심 정보를 담고 있는MANIFEST.MF파일Start-Class패러미터 : 어플리케이션을 시작할 클래스를 지정Main-Class패러미터 :Start-Class를 사용해서 어플리케이션을 시작하는Launcher클래스를 지정
- 스프링부트 로더 컴포넌트 :
JAR/WAR파일을 로딩하는JarLauncher/WarLauncher클래스loader.*프로퍼티에 값을 지정하면,PropertiesLauncher클래스로 클래스 로딩 과정 커스텀마이징 가능
BOOT-INF/classes: 컴파일된 모든 어플리케이션 클래스가 위치한 디렉터리BOOT-INF/lib: 의존 관계로 지정한 라이브러리가 들어있는 디렉터리classpath.idx: 클래스로더가 로딩해야 하는 순서대로 정렬된 의존 관계 목록이 들어있음layer.idx: 도커 이미지를 생성할 때 논리적 계층으로JAR를 분할할 때 사용
안전 종료 (
Graceful shutdown) : 처리 중인 요청이 완료될 때까지 기다릴 타임아웃 설정
- 어플리케이션을 종료할 때, 처리 중인 요청의 처리가 보장되지 않음
- 종료 명령어 실행되면 더 이상의 요청을 받지 않되, 이미 처리 중인 요청은 완료를 보장해야 함
- 스프링부트
2.3.0부터 도입되어, 그 이전 버전에서는 동작하지 않음server.shutdown=graceful # 기본값: immediate spring.lifecycle.timeout-per-shutdown-phase=1m # 기본값: 30s
스프링부트 스타트업 이벤트 : 스프링 어플리케이션 시작 및 초기화 과정에서 사용 가능한 빌트인 이벤트
ApplicationStartingEvent: 어플리케이션이 시작되어 리스너 (Listener가 등록될 때 발행- 스프링부트의
LoggingSystem이 해당 이벤트를 통해 어플리케이션 초기화 단계 이전에 필요한 작업 수행
- 스프링부트의
ApplicationEnvironmentPreparedEvent: 어플리케이션이 시작되고Environment가 준비될 때 발행MessageConverter,ConversionService,Jackson초기화 등 사전 초기화 (PreInitialize) 작업 수행
ApplicationContextInitializedEvent:ApplicationContext가 준비되고ApplicationContextInitializer가 실행되면 발행- 빈이 스프링 컨테이너에 로디오디어 초기화되기 전에 이루어질 작업이 필요할 때 이 이벤트를 사용
ApplicationPreparedEvent:ApplicationContext가 준비되고ApplicationContext가 초기화되기 전에 발행- 이 이벤트가 발행된 이후에
Environment를 사용할 수 있음
- 이 이벤트가 발행된 이후에
ContextRefreshedEvent:ApplicationContext가 초기화된 이후에 발행- 스프링부트가 아닌 스프링이 발행한 이벤트로,
SpringApplicationEvent를 상속하지 않음 - 스프링부트의
ConditionEvaluationLoggingListener가 이 이벤트가 발행되면 자동 구성 보고서를 출력
- 스프링부트가 아닌 스프링이 발행한 이벤트로,
WebServerInitializedEvent: 웹 서버가 준비되면 발행- 스프링부트가 아닌 스프링이 발행한 이벤트로,
SpringApplicationEvent를 상속하지 않음 - 어플리케이션 타입에 따른 하위 이벤트가 존재 (
ServletServerInitializedEvent,ReactiveServerInitializedEvent)
- 스프링부트가 아닌 스프링이 발행한 이벤트로,
ApplicationStartedEvent:ApplicationContext가 초기화되고ApplicationRunner,CommandLineRunner가 호출되기 전에 발행ApplicationReadyEvent: 어플리케이션 요청 처리가 준비되었을 때SpringApplication에 의해 발행- 모든 어플리케이션 초기화가 완료된 이후에 발행 : 이후에 어플리케이션 내부 상태를 변경하는 것은 권장되지 않음
ApplicationFailedEvent: 어플리케이션 시작 과정에서 예외가 발생하면 발행- 예외 발생 시 스크립트를 실행하거나, 스타트업 실패를 알릴 때 사용
스프링부트 어플리케이션 이벤트 감지 : 스타트업 이벤트가 제공하는 정보들을 활용하기 위한 이벤트 구독
@EventListener어노테이션 : 스프링 프레임워크에서 제공하는 이벤트를 구독하는 어노테이션- 어플리케이션 스타트업 극초기에 발행되는 이벤트는 감지하지 못함
# @EventListener를 사용해서 ApplicationReadyEvent를 구독
@EventListener(ApplicationReadyEvent.class)
public void funcForApplicationReadyEvent(ApplicationReadyEvent applicationReadyEvent) {
System.out.println("ApplicationReadyEvent generated at "
+ new Date(funcForApplicationReadyEvent.getTimestamp()));
}
SpringApplication클래스 : 어플리케이션 스타트업을 커스텀마이징할 수 있는setter메소드를 통해 리스너 등록ApplicationListener인터페이스의onApplicationEvent메소드를 구현해SpringApplication에 추가SpringApplication에 리스너를 등록하거나 수정하는 것은 클래스 코드의 변경을 유발
# 커스텀 ApplicationListener 구현체 작성
public class ApplicationStartEventListener
implements ApplicationListener<ApplicationStartingEvent> {
@Override
public void onApplicationEvent(ApplicationStartingEvent applicationStartingEvent) {
System.out.println("Application Starting Event logged at "
+ new Date(applicationStartingEvent.getTimestamp()));
}
}
# SpringApplication에 어플리케이션 이벤트 리스너 추가
@SpringBootApplication
public class SpringBootEventApplication {
public static void main(String[] args) {
SpringApplication springApplication
= new SpringApplication(SpringBootEventApplication.class);
}
}
spring.factories파일 : 어플리케이션 기능 설정 및 커스터마이징을 가능하도록 스프링부트가 제공스프링부트 이전부터 스프링 프레임워크에서 제공 (spring-beans.jar에서 확인 가능)
→ 스프링부트2.7.0부터deprecated
Reference