Spring Boot / / 2024. 10. 21. 11:14

SpringApplication.run()

SpringApplication.run()은 Spring Boot 애플리케이션의 시작점으로, 애플리케이션을 실행하고 스프링 컨테이너를 초기화하는 역할을 해. 이 메서드는 Spring Boot의 핵심 중 하나로, 다양한 설정을 자동으로 해주고 애플리케이션을 간편하게 실행할 수 있게 해줘.

 

SpringApplication.run()의 주요 역할:

 

1. SpringApplication 객체 생성

SpringApplication.run() 메서드는 내부적으로 SpringApplication 객체를 생성해. 이 객체는 애플리케이션의 실행 환경을 설정하고, 그 설정을 바탕으로 애플리케이션을 부트스트랩(시작)하는 역할을 해.

2. 애플리케이션 컨텍스트 생성

SpringApplication 객체가 생성되면 Spring 애플리케이션 컨텍스트를 만드는데, 이 컨텍스트는 스프링의 핵심 개념인 IOC 컨테이너 역할을 해. 이 컨텍스트 안에서 모든 스프링 빈(Bean)이 관리되고 의존성이 주입돼.

AnnotationConfigApplicationContext, ServletWebServerApplicationContext 같은 컨텍스트가 상황에 따라 선택돼. 웹 애플리케이션이라면 웹 컨텍스트가 생성되고, 일반 Java 애플리케이션이라면 일반 컨텍스트가 생성돼.

3. 애플리케이션 설정 및 초기화

스프링 부트의 자동 설정(Auto Configuration)이 이 단계에서 활성화돼. @SpringBootApplication 어노테이션이 이 과정에서 중요한 역할을 하는데, 이 어노테이션이 있는 클래스는 자동으로 컴포넌트 스캔을 실행해, 프로젝트의 모든 스프링 빈을 찾아서 등록해.

또한, 이 단계에서 **프로파일(Profile)**과 **환경 설정(Environment)**이 초기화돼. application.propertiesapplication.yml 파일에 정의된 설정들이 읽혀지고, 필요한 설정이 적용돼.

4. 내장 웹 서버(Tomcat, Jetty 등) 실행

만약 웹 애플리케이션을 실행하고 있다면, 이 과정에서 내장 웹 서버가 자동으로 시작돼. 기본적으로 Spring Boot는 내장 Tomcat 서버를 사용하지만, 설정에 따라 JettyUndertow 같은 다른 서버로 변경할 수도 있어.

내장 웹 서버는 8080 포트에서 애플리케이션을 실행하고 클라이언트의 요청을 받을 준비를 해.

5. CommandLineRunners 및 ApplicationRunners 실행

만약 애플리케이션에 CommandLineRunnerApplicationRunner 인터페이스를 구현한 빈이 있다면, 이 단계에서 그들이 실행돼. 이를 통해 애플리케이션이 시작된 직후에 어떤 로직을 실행할 수 있어.

예를 들어, 특정 데이터를 초기화하거나 로깅을 설정하는 작업을 할 수 있어.

6. ApplicationContext 반환

SpringApplication.run() 메서드는 실행된 애플리케이션의 ApplicationContext 객체를 반환해. 이 컨텍스트는 애플리케이션의 전체 상태와 모든 빈을 관리하는 역할을 하는데, 필요하면 이 컨텍스트를 통해 빈에 접근할 수 있어.

 

SpringApplication.run() 실행 과정:

 

1. 애플리케이션 부트스트랩 (Bootstrap):

애플리케이션을 실행하고 필요한 설정을 읽어들이며 초기화 과정을 시작해.

2. 애플리케이션 컨텍스트 생성:

스프링 애플리케이션 컨텍스트를 생성하고, 빈을 등록하며 의존성을 주입해.

3. 내장 웹 서버 실행 (웹 애플리케이션일 경우):

내장된 톰캣이나 젯티 서버를 실행해서 애플리케이션이 HTTP 요청을 처리할 수 있도록 준비해.

4. 스프링 컨테이너 초기화 완료:

모든 설정이 완료되면 애플리케이션이 시작되고, 요청을 받을 준비를 마쳐.

 

코드 예시:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

 

위 코드에서 SpringApplication.run(MyApplication.class, args)는 다음 역할을 수행해:

 

MyApplication 클래스를 기준으로 스프링 부트를 시작

args는 커맨드라인에서 입력된 인자들을 전달

애플리케이션 실행 및 모든 설정 자동화

 

요약:

 

SpringApplication.run()스프링 부트 애플리케이션의 시작점으로, 애플리케이션을 실행하고 컨텍스트를 초기화하는 핵심 메서드야.

자동 설정, 내장 웹 서버 실행, 빈 초기화 등의 작업을 수행하고, 애플리케이션이 요청을 받을 수 있도록 모든 준비를 마쳐.


SpringApplication.run()에 대해 좀 더 깊이 들어가 보면, 추가적인 동작이 있고, 다양한 커스터마이징 포인트가 있어. 

 

1. Banner 설정

 

기본적으로 SpringApplication.run()은 실행될 때 아까 말한 Spring Boot 배너를 표시하는데, 이 배너는 커스터마이징할 수 있어. 배너를 끄거나 커스텀 텍스트로 변경할 수 있어.

배너를 끄는 방법:

spring.main.banner-mode=off

 

배너를 커스텀하기:

src/main/resources/banner.txt 파일을 만들고, 원하는 텍스트나 ASCII 아트를 넣으면 실행 시 이 배너가 표시돼.

 

2. Application Event and Listeners

 

SpringApplication.run()이 실행되는 동안 여러 가지 이벤트가 발생해. 애플리케이션이 시작되기 전, 시작된 후, 컨텍스트가 준비된 후 등 다양한 시점에 이벤트가 발생하며, 이를 ApplicationListener로 처리할 수 있어.

몇 가지 주요 이벤트:

ApplicationStartingEvent: 애플리케이션이 시작될 때 발생

ApplicationEnvironmentPreparedEvent: 환경(Environment)이 준비된 후 발생

ApplicationPreparedEvent: 애플리케이션 컨텍스트가 준비된 후 발생

ApplicationStartedEvent: 애플리케이션이 완전히 시작된 후 발생

ApplicationReadyEvent: 애플리케이션이 사용 준비된 상태에서 발생

ApplicationFailedEvent: 애플리케이션이 시작 중에 실패할 때 발생

이벤트 리스너를 추가하려면:

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(MyApplication.class);
        app.addListeners(new MyApplicationListener());
        app.run(args);
    }
}

 

3. CommandLineRunner와 ApplicationRunner

 

Spring Boot는 CommandLineRunnerApplicationRunner 인터페이스를 통해 애플리케이션이 완전히 시작된 후 추가 작업을 할 수 있어. SpringApplication.run() 메서드 이후, 초기화 코드나 데이터를 넣을 때 유용하게 사용할 수 있지.

CommandLineRunner: 문자열 배열 args로 명령어 인수를 받아서 처리

ApplicationRunner: ApplicationArguments 객체를 받아 더 구조화된 형태로 명령어 인수를 처리

 

예시:

@Component
public class MyCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("애플리케이션 실행 후 추가 작업 수행");
    }
}

 

 

4. Failure Analyzer

 

SpringApplication.run()이 실패할 경우, 스프링 부트는 FailureAnalyzer를 통해 구체적인 오류 메시지를 제공해. 일반적인 애플리케이션 오류에서 사용자가 이해하기 쉬운 형태로 정보를 제공하는 것이 목적이야.

예를 들어, 데이터베이스 연결 오류나 잘못된 환경 설정이 있을 경우 오류 메시지가 친절하게 설명돼서 문제를 해결하는 데 도움이 돼.

 

5. SpringApplicationBuilder를 통한 커스터마이징

 

SpringApplication.run() 대신에 SpringApplicationBuilder를 사용할 수 있어. 이 빌더는 더 세부적인 설정을 할 수 있는 방법을 제공하지.

SpringApplicationBuilder로 애플리케이션의 여러 설정을 체인 방식으로 추가하거나 다른 설정을 쉽게 할 수 있어.

new SpringApplicationBuilder(MyApplication.class)
        .bannerMode(Banner.Mode.OFF)
        .profiles("prod")
        .run(args);

 

6. Application Arguments

 

SpringApplication.run()에 전달된 명령줄 인수ApplicationArguments로 접근할 수 있어. 이를 통해 명령어로 전달된 인수들을 처리할 수 있어.

@AutowiredApplicationArguments를 받아서 사용할 수 있지.

@Autowired
public MyRunner(ApplicationArguments args) {
    boolean debug = args.containsOption("debug");
    List<String> files = args.getNonOptionArgs();
}

 

7. Default Properties 설정

 

SpringApplication.run()은 실행될 때 기본 프로퍼티를 설정할 수 있어. application.properties 파일 외에도, 코드를 통해서 기본값을 설정할 수 있지.

SpringApplication app = new SpringApplication(MyApplication.class);
Map<String, Object> defaultProperties = new HashMap<>();
defaultProperties.put("server.port", "8083");
app.setDefaultProperties(defaultProperties);
app.run(args);

 

8. Exit 코드 처리

 

스프링 부트 애플리케이션이 종료될 때 종료 코드를 설정할 수 있어. 예를 들어, 애플리케이션이 정상적으로 종료되었는지, 또는 에러가 발생했는지에 따라 종료 코드를 반환할 수 있어.

SpringApplication.exit() 메서드를 사용해서 애플리케이션 종료 시 적절한 종료 코드를 반환할 수 있지.

ConfigurableApplicationContext ctx = SpringApplication.run(MyApplication.class, args);
System.exit(SpringApplication.exit(ctx, () -> 0));

 

요약:

 

배너 커스터마이징: 배너를 끄거나 커스텀할 수 있어.

이벤트 리스너: 애플리케이션의 다양한 상태에서 발생하는 이벤트를 처리할 수 있어.

CommandLineRunner와 ApplicationRunner: 애플리케이션 시작 후 실행할 로직을 정의할 수 있어.

Failure Analyzer: 친절한 오류 메시지로 문제를 해결하는 데 도움을 줘.

SpringApplicationBuilder: 더 세밀하게 애플리케이션을 설정할 수 있어.

명령어 인수 처리: ApplicationArguments로 명령어 인수를 처리할 수 있어.

기본 프로퍼티 설정: 실행 중에 기본 프로퍼티를 설정할 수 있어.

Exit 코드 처리: 종료 시 적절한 종료 코드를 반환할 수 있어.


전체적인 SpringApplication 동작 흐름

 

1. 시작 시간 기록

애플리케이션이 실행되는 시간을 계산하기 위해 시작 시간을 기록해 두는 단계야.

long startTime = System.nanoTime();

 

2. Bootstrap 컨텍스트 생성

Spring Boot 초기화 과정에서 필요한 리소스와 설정을 제공하는 부트스트랩 컨텍스트를 생성해.

DefaultBootstrapContext bootstrapContext = createBootstrapContext();

 

3. Headless 모드 설정

서버 환경에서 불필요한 GUI 리소스를 차단하기 위해 Headless 모드를 설정해. 서버 환경에서는 GUI 관련 리소스가 필요 없으니까, 이를 비활성화하는 거야.

configureHeadlessProperty();

 

4. Run Listener 초기화 및 시작 알림

애플리케이션 실행 중 특정 이벤트를 감지하는 리스너들을 초기화하고, 애플리케이션이 시작된다는 사실을 알리는 단계야.

SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);

 

5. 애플리케이션 아규먼트 처리

main() 메서드에서 전달된 아규먼트를 처리하는 단계야. 전달된 값들이 애플리케이션의 설정에 영향을 줄 수 있어.

ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

 

7. 배너 출력

Spring Boot를 실행하면 보이는 그 멋진 ASCII 아트 배너를 출력하는 단계야. 이 배너는 사용자 정의도 가능해.

Banner printedBanner = printBanner(environment);

 

8. ApplicationContext 생성

실제로 애플리케이션에서 빈(Bean)들을 관리하고 조립하는 핵심 컨텍스트를 생성해. 이 컨텍스트는 Spring의 기본 기능을 담당하는 중요한 부분이야.

context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);

 

9. ApplicationContext 초기화 준비

ApplicationContext를 실제로 사용할 수 있도록 초기화하고, 환경 설정, 리스너, 아규먼트를 전달하는 단계야.

prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);

 

10. ApplicationContext 새로 고침

ApplicationContext를 새로 고침해서 모든 빈들을 로딩하고, 의존성을 주입해.

refreshContext(context);

 

11. 애플리케이션 시작 후 처리

컨텍스트가 완전히 초기화된 후에 추가적으로 필요한 작업들을 처리하는 단계야.

afterRefresh(context, applicationArguments);

 

12. 시작 정보 로깅

애플리케이션이 시작하는 데 걸린 시간을 계산해서, 그 정보를 로그로 남기는 단계야.

Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);

 

13. 리스너에게 시작 완료 알림

리스너들에게 애플리케이션이 성공적으로 시작되었다고 알리는 단계야.

listeners.started(context, timeTakenToStartup);

 

14. CommandLineRunner 및 ApplicationRunner 실행

Spring Boot 애플리케이션에서 특정 작업을 수행하기 위한 CommandLineRunner 또는 ApplicationRunner를 실행해.

callRunners(context, applicationArguments);

 

15. 예외 처리

애플리케이션 실행 중에 발생할 수 있는 예외를 처리하는 단계야. 예외가 발생하면 리스너에게 실패 이벤트를 알리고, 필요하면 예외를 다시 던져.

catch (Throwable ex) {
    handleRunFailure(context, ex, listeners);
    throw new IllegalStateException(ex);
}

 

16. 애플리케이션 준비 완료 알림

애플리케이션이 준비 완료되었음을 리스너에게 알리고, 필요한 후속 작업을 수행할 수 있게 해.

if (context.isRunning()) {
    listeners.ready(context, Duration.ofNanos(System.nanoTime() - startTime));
}

 

17. 컨텍스트 반환

최종적으로 애플리케이션 컨텍스트를 반환해서, 애플리케이션이 계속 실행되도록 하고, 외부에서 상태를 확인할 수 있게 해.

return context;

 

이 과정에서 중요한 점은 ApplicationContext가 모든 빈을 관리하고 애플리케이션 로직을 수행하기 위해 모든 단계가 준비된다는 거야.

'Spring Boot' 카테고리의 다른 글

@Import  (0) 2024.10.21
Spring Boot의 Auto-Configuration  (2) 2024.10.21
@SpringBootApplication  (0) 2024.10.21
Spring Native  (0) 2024.10.21
Spring Boot  (2) 2024.10.21
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유