[Spring Boot ์‹œ์ž‘ ๊ณผ์ •] 2. Application Bootstraping์„ ์œ„ํ•œ 13๋‹จ๊ณ„

SpringApplication ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋œ ํ›„ ์ธ์Šคํ„ด์Šค์˜ run() ํ˜ธ์ถœ์‹œ(์ •์  ๋ฉ”์„œ๋“œ run()์ด ์•„๋‹ˆ๋‹ค) Application Bootstraping์„ ์œ„ํ•œ 13๋‹จ๊ณ„๋ฅผ ๊ฑฐ์น˜๋Š”๋ฐ ์–ด๋–ค ๊ณผ์ •๋“ค์„ ์ˆ˜ํ–‰ํ•˜๋Š”์ง€ ์•Œ์•„๋ณด์ž. SpringApplication ํด๋ž˜์Šค ์ฝ”๋“œ๋Š” Spring Boot 3.2.1 ๋ฒ„์ „์„ ์‚ฌ์šฉํ•˜์˜€๋‹ค.

๋จผ์ € ๋ณด๋ฉด ์ข‹์€ ํฌ์ŠคํŒ…
Spring Boot ์‹œ์ž‘ โ€“ SpringApplication ์ƒ์„ฑ๊ณผ ์ž๋™ ๊ฐ์ง€

Application Bootstraping ๊ณผ์ •์˜ 13๋‹จ๊ณ„

Spring Boot ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์‹œ์ž‘ ๊ณผ์ •์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ 13๊ฐœ์˜ ์ฃผ์š” ๋‹จ๊ณ„๋กœ ๊ตฌ์„ฑ๋œ๋‹ค.
์šฐ์„  SpringApplication์˜ run() ๋ฉ”์„œ๋“œ(์ •์  ๋ฉ”์„œ๋“œ ์•„๋‹˜)๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

public ConfigurableApplicationContext run(String... args) {
    // startup ๊ฐ์ฒด ์ƒ์„ฑ
    Startup startup = Startup.create();
    // shutdown ํ›… ์„ค์ •
    if (this.registerShutdownHook) {
       SpringApplication.shutdownHook.enableShutdownHookAddition();
    }
    // BootstrapContext ์ƒ์„ฑ
    DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    // headless ๋ชจ๋“œ ์„ค์ •
    ConfigurableApplicationContext context = null;
    configureHeadlessProperty();
    // ์‹œ์ž‘ ๊ณผ์ •์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๊ธฐ ์œ„ํ•œ ๋ฆฌ์Šค๋„ˆ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting(bootstrapContext, this.mainApplicationClass);
    try {
       // ๋ช…๋ นํ–‰ ์ธ์ˆ˜๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  ํ™˜๊ฒฝ ๊ฐ์ฒด๋ฅผ ์ค€๋น„ํ•œ๋‹ค.
       ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
       ConfigurableEnvironment environment =
                    prepareEnvironment(listeners, bootstrapContext, applicationArguments);
       // ๋ฐฐ๋„ˆ ์ถœ๋ ฅ
       Banner printedBanner = printBanner(environment);
       // ApplicationContext ์ค€๋น„
       context = createApplicationContext();
       context.setApplicationStartup(this.applicationStartup);
       prepareContext(bootstrapContext, context, environment,
                      listeners, applicationArguments, printedBanner);
       // ApplicationContext refresh
       refreshContext(context);
       // refresh ์ดํ›„ ์ฒ˜๋ฆฌ ์ž‘์—…
       afterRefresh(context, applicationArguments);
       // ์‹œ์ž‘ ์‹œ๊ฐ„ ๊ณ„์‚ฐ ๋ฐ ๋กœ๊น…
       startup.started();
       if (this.logStartupInfo) {
          new StartupInfoLogger(this.mainApplicationClass)
                .logStarted(getApplicationLog(), startup);
       }
       // ์‹œ์ž‘ ์™„๋ฃŒ ์ด๋ฒคํŠธ ๋ฐœ์ƒ
       listeners.started(context, startup.timeTakenToStarted());
       // ApplicationRunner์™€ CommandLineRunner ์‹คํ–‰
       callRunners(context, applicationArguments);
    }
    catch (Throwable ex) {
       if (ex instanceof AbandonedRunException) {
          throw ex;
       }
       handleRunFailure(context, ex, listeners);
       throw new IllegalStateException(ex);
    }
    // ์ค€๋น„์™„๋ฃŒ ์ด๋ฒคํŠธ ๋ฐœ์ƒ
    try {
       if (context.isRunning()) {
          listeners.ready(context, startup.ready());
       }
    }
    catch (Throwable ex) {
       if (ex instanceof AbandonedRunException) {
          throw ex;
       }
       handleRunFailure(context, ex, null);
       throw new IllegalStateException(ex);
    }
    return context;
}
Java

1๋‹จ๊ณ„: Startup ๊ฐ์ฒด ์ƒ์„ฑ

Startup startup = Startup.create();
Java

์‹œ์ž‘ ์‹œ๊ฐ„์„ ์ถ”์ ํ•˜๊ธฐ ์œ„ํ•œ Startup ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ์ด๋Š” Spring Boot 3.X์—์„œ ๋„์ž…๋œ ์ƒˆ๋กœ์šด ์‹œ๊ฐ„ ์ถ”์  ๋ฉ”์นด๋‹ˆ์ฆ˜์„ ์‚ฌ์šฉํ•œ๋‹ค.

2๋‹จ๊ณ„: ์…ง๋‹ค์šด ํ›… ์„ค์ •

if (this.registerShutdownHook) {
   SpringApplication.shutdownHook.enableShutdownHookAddition();
}
Java

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ข…๋ฃŒ ์‹œ ์ •๋ฆฌ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์…ง๋‹ค์šด ํ›…์„ ํ™œ์„ฑํ™” ํ•œ๋‹ค. setRegisterShutdownHook(false) ํ˜ธ์ถœ๋กœ ๋น„ํ™œ์„ฑํ™” ํ•  ์ˆ˜ ์žˆ๋‹ค. registerShutdownHook์ด true์ธ ๊ฒฝ์šฐ(๋””ํดํŠธ true) ์ƒ์„ฑ๋œ ApplicationContext์— ์ข…๋ฃŒ ํ›…์ด ๋“ฑ๋ก๋œ๋‹ค. JVM ์ข…๋ฃŒ๊ฐ€ ์›ํ™œํ•˜๊ฒŒ ์ฒ˜๋ฆฌ๋˜๋„๋ก ๊ธฐ๋ณธ๊ฐ’์€ true๋กœ ์„ค์ •๋œ๋‹ค.

3๋‹จ๊ณ„: BootstrapContext ์ƒ์„ฑ

DefaultBootstrapContext bootstrapContext = createBootstrapContext();
Java

ApplicationContext๊ฐ€ ์ƒ์„ฑ๋˜๊ธฐ ์ „๊นŒ์ง€ ํ•„์š”ํ•œ ์„œ๋น„์Šค๋“ค์„ ์ œ๊ณตํ•˜๋Š” Bootstrap Context๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
BootstrapContext๋Š” ApplicationContext๊ฐ€ ์ƒ์„ฑ๋˜๊ธฐ ์ „ ๋‹จ๊ณ„์—์„œ ํ•„์š”ํ•œ ์„œ๋น„์Šค๋“ค์„ ์ œ๊ณตํ•˜๋Š” ์ž„์‹œ ์ปจํ…Œ์ด๋„ˆ ์—ญํ• ์„ ํ•œ๋‹ค.
BootstrapContext๊ฐ€ ํ•„์š”ํ•œ ์ด์œ ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • ApplicationContext ์ƒ์„ฑ์—๋Š” ์‹œ๊ฐ„์ด ๊ฑธ๋ฆผ(Bean ์Šค์บ”, ์ž๋™ ๊ตฌ์„ฑ๋“ฑ)
  • ํ•˜์ง€๋งŒ ApplicationContext ์ƒ์„ฑ ๊ณผ์ •์—์„œ๋„ ์ผ๋ถ€ ์„œ๋น„์Šค๊ฐ€ ํ•„์š”ํ•จ
  • ์˜ˆ: ํ™˜๊ฒฝ ์„ค์ • ๋กœ๋”ฉ, ์™ธ๋ถ€ ๊ตฌ์„ฑ ์„œ๋ฒ„ ์—ฐ๊ฒฐ, ๋ณด์•ˆ ์„ค์ •๋“ฑ

BootstrapContext vs ApplicationContext

ํŠน์„ฑBootstrapContextApplicationContext
์ƒ์„ฑ ์‹œ์ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์งํ›„๋ถ€ํŠธ์ŠคํŠธ๋žฉ ๊ณผ์ • ์ค‘๋ฐ˜
์ƒ๋ช… ์ฃผ๊ธฐ์งง์Œ(ApplicationContext ์ƒ์„ฑ ํ›„ ์†Œ๋ฉธ)์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์ฒด
์šฉ๋„์ดˆ๊ธฐ์„ค์ •, ์™ธ๋ถ€ ์„œ๋น„์Šค ์—ฐ๊ฒฐ๋ชจ๋“  Bean ๊ด€๋ฆฌ
์„œ๋น„์Šค ์ˆ˜์ ์Œ (ํ•„์ˆ˜์ ์ธ ๊ฒƒ๋งŒ)๋งŽ์Œ (์ „์ฒด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜)
์˜์กด์„ฑ ์ฃผ์ž…์ˆ˜๋™ ๋“ฑ๋ก์ž๋™ ์ฃผ์ž…

๋‹ญ๊ณผ ๋‹ฌ๊ฑ€ ๋ฌธ์ œ ํ•ด๊ฒฐ

๋ถ€ํŠธ์ŠคํŠธ๋ž˜ํ•‘์—์„œ ๊ณผ์ •์—์„œ ๊ฐ€์žฅ ํฅ๋ฏธ๋กœ์šด ์š”์†Œ ์ค‘ ํ•˜๋‚˜๊ฐ€ ๋ฐ”๋กœ BootstrapContext์ด๋‹ค.
ApplicationContext๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„œ๋Š” ์„ค์ •(Configuration)์ด ํ•„์š”ํ•˜๋‹ค. ํ•˜์ง€๋งŒ ์„ค์ •์„ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด์„œ ์™ธ๋ถ€ ์„œ๋น„์Šค(์˜ˆ: Spring Cloud Config)์— ์—ฐ๊ฒฐํ•˜๋ ค๋ฉด ๋˜ ๋‹ค๋ฅธ ๊ฐ์ฒด๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ์ด๋Ÿฌํ•œ ์ˆœํ™˜ ์˜์กด์„ฑ์„ ๋Š๊ธฐ ์œ„ํ•ด Spring Boot๋Š” BootstrapContext ์žฅ์น˜๋ฅผ ๋งˆ๋ จํ–ˆ๊ณ  ์ด๋Š” ApplicationContext ์ƒ์„ฑ์— ํ•„์š”ํ•œ ์ตœ์†Œํ•œ์˜ ์„œ๋น„์Šค๋“ค์„ ๋ฏธ๋ฆฌ ์ค€๋น„ํ•ด๋‘๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.

4๋‹จ๊ณ„: ํ—ค๋“œ๋ฆฌ์Šค ๋ชจ๋“œ ์„ค์ •

configureHeadlessProperty();
Java

GUI๊ฐ€ ์—†๋Š” ์„œ๋ฒ„ ํ™˜๊ฒฝ์—์„œ ์‹คํ–‰๋จ์„ ์‹œ์Šคํ…œ์— ์•Œ๋ฆฌ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค. ์ด ๋ฉ”์„œ๋“œ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ java.awt.headless ์‹œ์Šคํ…œ ํ”„๋กœํผํ‹ฐ๋ฅผ true๋กœ ์„ค์ •ํ•œ๋‹ค.

5๋‹จ๊ณ„: SpringApplicationRunListeners ํš๋“ ๋ฐ ์‹œ์ž‘ ์ด๋ฒคํŠธ ๋ฐœํ–‰

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

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ๊ณผ์ •์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•  ๋ฆฌ์Šค๋„ˆ๋“ค์„ ๊ฐ€์ ธ์˜ค๊ณ , ApplicationStartingEvent๋ฅผ ๋ฐœํ–‰ํ•œ๋‹ค.

6๋‹จ๊ณ„: ApplicationArguments ์ƒ์„ฑ ๋ฐ Environment ์ค€๋น„

ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = 
                    prepareEnvironment(listeners, bootstrapContext, applicationArguments);
Java

๋ช…๋ นํ–‰ ์ธ์ˆ˜๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  Environment ๊ฐ์ฒด๋ฅผ ์ค€๋น„ํ•œ๋‹ค.
์ด ๋‹จ๊ณ„์—์„œ๋Š” ๋‹ค์Œ ์ž‘์—…๋“ค์ด ์ˆ˜ํ–‰๋œ๋‹ค.

Environment ๊ฐ์ฒด ์ƒ์„ฑ

  • ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํƒ€์ž…์— ๋”ฐ๋ผ ์ ์ ˆํ•œ Environment ๊ตฌํ˜„์ฒด ์ƒ์„ฑ
  • StandardServletEnvironment, StandardReactiveWebEnvironment ๋“ฑ

ํ”„๋กœํผํ‹ฐ ์†Œ์Šค ๊ตฌ์„ฑ

  • application.properties/yml ํŒŒ์ผ ๋กœ๋“œ
  • ํ™˜๊ฒฝ๋ณ€์ˆ˜, ์‹œ์Šคํ…œ ํ”„๋กœํผํ‹ฐ, ๋ช…๋ นํ–‰ ์ธ์ˆ˜ ๋“ฑ์„ ์šฐ์„ ์ˆœ์œ„์— ๋”ฐ๋ผ ๊ตฌ์„ฑ

Environment ์ค€๋น„ ์™„๋ฃŒ ์ด๋ฒคํŠธ ๋ฐœํ–‰

listeners.environmentPrepared(bootstrapContext, environment);
Java

์œ„ ์ฝ”๋“œ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ EventPublishingRunListener ํด๋ž˜์Šค์˜ environmentPrepared ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š”๋ฐ ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

@Override
	public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
			ConfigurableEnvironment environment) {
		multicastInitialEvent(
				new ApplicationEnvironmentPreparedEvent(bootstrapContext, this.application, this.args, environment));
	}
Java

์œ„ ์ฝ”๋“œ๋Š” SpringApplication ์ธ์Šคํ„ด์Šค์— ๋“ฑ๋ก๋œ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋“ค์—๊ฒŒ ApplicationEnvironmentPreparedEvent๋ฅผ ์ „๋‹ฌํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค. ์ด ์‹œ์ ์€ ์‹ค์ œ Spring Bean๋“ค์ด ์ƒ์„ฑ๋˜๊ธฐ ์ „์ด๋ฏ€๋กœ ์ด ์ด๋ฒคํŠธ๋ฅผ ๊ตฌ๋…ํ•˜๋Š” ๋ฆฌ์Šค๋„ˆ๋“ค์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ดˆ๊ธฐํ™” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

  • ํ”„๋กœํŒŒ์ผ(Profiles) ์„ค์ •: spring.profiles.active ์„ค์ •์„ ํ™•์ธํ•˜์—ฌ ์–ด๋–ค ํ™˜๊ฒฝ(dev, local, prod๋“ฑ)์œผ๋กœ ๊ตฌ๋™ํ• ์ง€ ๊ฒฐ์ •ํ•œ๋‹ค.
  • ํ›„์ฒ˜๋ฆฌ ์ž‘์—…: ํŠน์ • ํ™˜๊ฒฝ ๋ณ€์ˆ˜์— ๋”ฐ๋ผ ์‹œ์Šคํ…œ ์†์„ฑ์„ ๋™์ ์œผ๋กœ ๋ณ€๊ฒฝํ•ด์•ผ ํ•  ๋•Œ ์ด ์‹œ์ ์„ ํ™œ์šฉํ•œ๋‹ค.

๋˜ํ•œ ApplicationListener<ApplicationEnvironmentPreparedEvent>๋ฅผ ๊ตฌํ˜„ํ•œ ์ปค์Šคํ…€ ๋ฆฌ์Šค๋„ˆ๋ฅผ ๋“ฑ๋กํ•˜์—ฌ ํ™˜๊ฒฝ ์„ค์ •์ด ์™„๋ฃŒ๋œ ํ›„์— ์›ํ•˜๋Š” ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

7๋‹จ๊ณ„: Banner ์ถœ๋ ฅ

Banner printedBanner = printBanner(environment);
Java

Spring Boot์˜ ์‹œ์ž‘ ๋ฐฐ๋„ˆ๋ฅผ ์ฝ˜์†”์— ์ถœ๋ ฅํ•œ๋‹ค. spring.main.banner-mode๋กœ ์ œ์–ด๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

8๋‹จ๊ณ„: ApplicationContext ์ƒ์„ฑ

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

์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํƒ€์ž…์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ApplicationContext ๊ตฌํ˜„์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ApplicationStartup ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํƒ€์ž…ApplicationContext ๊ตฌํ˜„์ฒดํŠน์ง•
SERVLETAnnotationConfigServletWebServerApplicationContextํ†ฐ์บฃ ๋‚ด์žฅ ์„œ๋ธ”๋ฆฟ ์„œ๋ฒ„ ๊ด€๋ฆฌ
REACTIVEAnnotationConfigReactiveWebServerApplicationContext๋„คํ‹ฐ ๊ธฐ๋ฐ˜ ๋ฆฌ์•กํ‹ฐ๋ธŒ ์„œ๋ฒ„ ๋ฐ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ
NONEAnnotationConfigApplicationContext์›น ์„œ๋ฒ„ ์—†๋Š” ๊ฒฝ๋Ÿ‰ ๊ตฌ์กฐ

SERVLET ํƒ€์ž…์˜ ๊ฒฝ์šฐ ์ปจํ…์ŠคํŠธ์˜ onRefresh() ๋‹จ๊ณ„์—์„œ createWebServer()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋‚ด์žฅ ํ†ฐ์บฃ ์„œ๋ฒ„๋ฅผ ์‹ค์ œ ๊ธฐ๋™ํ•œ๋‹ค.

9๋‹จ๊ณ„: ApplicationContext ์ค€๋น„

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

ApplicationContext๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๊ณ  Bean ์ •์˜๋ฅผ ๋“ฑ๋กํ•œ๋‹ค. (Bean์„ ๋“ฑ๋กํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ Bean ์ƒ์„ฑ์„ ์œ„ํ•œ ์ •์˜๋ฅผ ๋กœ๋“œํ•˜๋Š” ๊ฒƒ์ด๋‹ค)
์ด ๋‹จ๊ณ„์—์„œ๋Š” ํ•ต์‹ฌ์ ์ธ ์—ฌ๋Ÿฌ ๋‹จ๊ณ„๋ฅผ ํฌํ•จํ•œ๋‹ค.
๋‹ค์Œ์€ prepareContext() ๋‚ด์—์„œ ์‹คํ–‰๋˜๋Š” ๋™์ž‘๋“ค์ด๋‹ค.

ApplicationContext์— Environment ์ฃผ์ž…

context.setEnvironment(environment);
Java

ApplicationContextInitializer ์‹คํ–‰

applyInitializers(context);
Java

์‚ฌ์šฉ์ž ์ •์˜ ApplicationContextInitializer๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค๋ฉด ์ด ๋‹จ๊ณ„์—์„œ ์‚ฌ์šฉ์ž ์ •์˜ ApplicationContextInitializer๊ฐ€ ์‹คํ–‰๋œ๋‹ค.

์ปจํ…์ŠคํŠธ ์ค€๋น„ ์™„๋ฃŒ ์ด๋ฒคํŠธ ๋ฐœํ–‰

listeners.contextPrepared(context);
Java

SpringApplication ์ธ์Šคํ„ด์Šค์— ๋“ฑ๋ก๋œ ๋ฆฌ์Šค๋„ˆ๋“ค์—๊ฒŒ ApplicationContextInitializedEvent๋ฅผ ์ „๋‹ฌํ•œ๋‹ค.

BootstrapContext ์ข…๋ฃŒ

bootstrapContext.close(context);
Java

์ปจํ…์ŠคํŠธ ๋กœ๋“œ ์™„๋ฃŒ ์ด๋ฒคํŠธ ๋ฐœํ–‰

listeners.contextLoaded(context);
Java

SpringApplication ์ธ์Šคํ„ด์Šค์— ๋“ฑ๋ก๋˜์–ด ์žˆ๋˜ ๋ฆฌ์Šค๋„ˆ๋“ค ์ค‘์—์„œ ApplicationContextAware ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ๋ฆฌ์Šค๋„ˆ๋ฅผ ์ฐพ์•„์„œ ๋ฐฉ๊ธˆ ๋กœ๋“œ๋œ ApplicationContext ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•˜๊ณ  ApplicationPreparedEvent๋ฅผ ๋ฐœํ–‰ํ•œ๋‹ค. ์ด ์ด๋ฒคํŠธ๋Š” Bean์ด ์‹ค์ œ๋กœ ์ƒ์„ฑ๋˜๊ธฐ ์ „์— ๋งˆ์ง€๋ง‰์œผ๋กœ ์„ค์ •์„ ์กฐ์ž‘ํ•ด์•ผ ํ•  ๊ธฐ๋Šฅ๋“ค์ด ์ˆ˜์‹ ํ•œ๋‹ค.
ApplicationListener<ApplicationPreparedEvent> ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ์‚ฌ์šฉ์ž ์ •์˜ ๊ตฌํ˜„์ฒด๋ฅผ SpringApplication ์ธ์Šคํ„ด์Šค์˜ addListener๋ฅผ ํ†ตํ•ด์„œ ๋“ฑ๋กํ•˜์—ฌ ApplicationPreparedEvent๋ฅผ ๋ฐ›์•„์„œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

10๋‹จ๊ณ„: ApplicationContext refresh

์ด ๋‹จ๊ณ„์—์„œ ๋“œ๋””์–ด Bean์„ ์ƒ์„ฑํ•˜๊ณ  ์˜์กด์„ฑ์„ ์ฃผ์ž…ํ•˜๋ฉฐ ์›น ์„œ๋ฒ„๋ฅผ ์‹œ์ž‘ํ•œ๋‹ค.

refreshContext(context);
Java

์ด ๋‹จ๊ณ„๊ฐ€ Spring Boot ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ธฐ๋™ ๊ณผ์ •์—์„œ ๊ฐ€์žฅ ํ•ต์‹ฌ์ ์ธ ๋‹จ๊ณ„๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.

  1. BeanFactory ์ค€๋น„ ๋ฐ PostProcessor ์‹คํ–‰
    • ApplicationContext ๋‚ด๋ถ€์˜ BeanFactory๋ฅผ ์ค€๋น„ํ•œ๋‹ค.
    • @Configuration ํด๋ž˜์Šค๋ฅผ ๋ถ„์„ํ•˜์—ฌ ์–ด๋–ค Bean๋“ค์„ ์ƒ์„ฑํ•ด์•ผ ํ• ์ง€ ์ตœ์ข… ๊ฒฐ์ •ํ•œ๋‹ค.
    • PropertySourcesPlaceholderConfigurer ๊ฐ™์€ ํ”„๋กœ์„ธ์„œ๊ฐ€ ๋™์ž‘ํ•˜์—ฌ Bean ์„ค์ •์— ํฌํ•จ๋œ ${…} ๊ฐ’๋“ค์„ ์‹ค์ œ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋กœ ์น˜ํ™˜ํ•œ๋‹ค.
  2. Bean ํ›„์ฒ˜๋ฆฌ๊ธฐ ๋“ฑ๋ก (registerBeanPostProcessors)
    • Bean์ด ์ƒ์„ฑ๋˜๊ธฐ ์ „๊ณผ ํ›„์— ๊ฐœ์ž…ํ•˜์—ฌ ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๊ฑฐ๋‚˜(AOP) ์ถ”๊ฐ€ ์„ค์ •์„ ์ฒ˜๋ฆฌํ•  BeanPostProcessor๋“ค์„ ๋จผ์ € ์ƒ์„ฑํ•˜์—ฌ ๋“ฑ๋กํ•œ๋‹ค.
    • BeanPostProcessors ์ธํ„ฐํŽ˜์ด์Šค์— ๋Œ€ํ•œ ์‚ฌ์šฉ์ž ์ •์˜ ๊ตฌํ˜„์ฒด ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์„œ ํŠน์ • Bean์— ๋Œ€ํ•œ ํŠน์ • ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ฑฐ๋‚˜ AOP๋ฅผ ์ ์šฉํ•œ ์ƒˆ๋กœ์šด Bean์„ ๋“ฑ๋กํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
  3. ๋‚ด์žฅ ์›น์„œ๋ฒ„ ๊ธฐ๋™ (onRefresh)
    • ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜(SERVLET, REACTIVE) ํƒ€์ž…์ธ ๊ฒฝ์šฐ Tomcat, Jetty, Netty์™€ ๊ฐ™์€ ๋‚ด์žฅ ์›น ์„œ๋ฒ„๋ฅผ ๊ธฐ๋™ํ•œ๋‹ค.
  4. ๋ชจ๋“  ์‹ฑ๊ธ€ํ†ค Bean์˜ ์ธ์Šคํ„ด์Šคํ™”
    • ๊ฐ€์žฅ ๋งŽ์€ ์‹œ๊ฐ„์ด ์†Œ์š”๋˜๋Š” ๊ตฌ๊ฐ„์ด๋‹ค.
    • ์ •์˜๋œ ๋ชจ๋“  ์‹ฑ๊ธ€ํ†ค Bean์„ ์‹ค์ œ ๋ฉ”๋ชจ๋ฆฌ์— ๋กœ๋“œํ•œ๋‹ค. (Instantiation)
    • Bean๋“ค ์‚ฌ์ด์˜ ์˜์กด์„ฑ ์ฃผ์ž…์ด ์ด๋ฃจ์–ด์ง„๋‹ค.
    • SpringApplication ์ธ์Šคํ„ด์Šค์—์„œ LazyInitialization ์†์„ฑ์ด false(๊ธฐ๋ณธ๊ฐ’)์ด๋ฉด ๋ชจ๋“  Bean์ด ์ด ๋‹จ๊ณ„์—์„œ ์ฆ‰์‹œ ์ƒ์„ฑ๋œ๋‹ค.
  5. refresh ์™„๋ฃŒ ๋ฐ ์ด๋ฒคํŠธ ๋ฐœํ–‰
    • ContextRefreshedEvent๋ฅผ ๋ฐœํ–‰ํ•˜์—ฌ ApplicationContext๊ฐ€ ์™„์ „ํžˆ ๊ฐ€๋™ ๋˜์—ˆ์Œ์„ ์•Œ๋ฆฐ๋‹ค.

11๋‹จ๊ณ„: ์‹œ์ž‘์‹œ๊ฐ„ ๊ณ„์‚ฐ ๋ฐ ๋กœ๊น…

Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
    new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}
Java

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์‹œ๊ฐ„์„ ๊ณ„์‚ฐํ•˜๊ณ  ๋กœ๊ทธ์— ๊ธฐ๋กํ•œ๋‹ค.

12๋‹จ๊ณ„: ApplicationRunner์™€ CommandLineRunner ์‹คํ–‰

callRunners(context, applicationArguments);
Java

ApplicationRunner์™€ CommandLineRunner ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ Bean๋“ค์„ ์ฐพ์•„ ์‹คํ–‰ํ•œ๋‹ค.

13๋‹จ๊ณ„: ์ค€๋น„ ์™„๋ฃŒ ์ด๋ฒคํŠธ ๋ฐœํ–‰

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

ApplicationReadyEvent๋ฅผ ๋ฐœํ–‰ํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์™„์ „ํžˆ ์ค€๋น„๋˜์—ˆ์Œ์„ ์•Œ๋ฆฐ๋‹ค.

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ ๊ณผ์ •์—์„œ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ์ƒ˜ํ”Œ

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ ๊ณผ์ •์—์„œ ์‚ฌ์šฉ์ž ์ •์˜ BootstrapInitializer๋ฅผ ๋“ฑ๋กํ•˜๊ณ  BootstrapContext์— ํด๋ž˜์Šค๋ฅผ ๋“ฑ๋กํ•˜์—ฌ EnvironmentPreparedEvent๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ์‚ฌ์šฉ์ž ์ •์˜ ๋ฆฌ์Šค๋„ˆ๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ BootstrapContext์— ๋“ฑ๋ก๋œ ๊ฐ’์„ Environment์— ์ถ”๊ฐ€ํ•˜๊ณ  ApplicationContext ์ƒ์„ฑ ์งํ›„์— ์‹คํ–‰๋˜๋Š” ApplicationContextInitializer๋ฅผ ๋“ฑ๋กํ•˜์—ฌ Environment์˜ ๊ฐ’์„ ๋กœ๊ทธ์— ๊ธฐ๋กํ•˜๋Š” ์ƒ˜ํ”Œ ์ฝ”๋“œ๋‹ค.

BootstrapInitializer(cpu core ๊ฐœ์ˆ˜ ์ฒดํฌ) 
--> BootstrapContext์— CPU-CORE-<cpu core ๊ฐœ์ˆ˜> ๋ฌธ์ž์—ด ๋“ฑ๋ก
--> EnvironmentPreparedEvent ๋ฆฌ์Šค๋„ˆ์—์„œ CPU-CORE-<cpu core ๊ฐœ์ˆ˜> ๊ฐ’์„ Environment์— ์ถ”๊ฐ€
--> ApplicationContextInitializer์—์„œ Environment๋กœ ๋ถ€ํ„ฐ ๋“ฑ๋ก๋œ CPU-CORE-<cpu core ๊ฐœ์ˆ˜> ๊ฐ’์„ ๋กœ๊น…
Plaintext

BootstrapInitializerCustom.java

@Slf4j
public class BootstrapInitializerCustom implements BootstrapRegistryInitializer {
/*
์ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ cpu core์ˆ˜๊ฐ€ ์ตœ์†Œ 3๊ฐœ ์ด์ƒ์ด ํ•„์š”ํ•˜๋‹ค.
BootstrapInitializer์—์„œ ApplicationContext๊ฐ€ ์ƒ์„ฑ๋˜๊ธฐ ์ „์— cpu core์ˆ˜๋ฅผ ๋ฏธ๋ฆฌ ํ™•์ธํ•œ๋‹ค.
cpu core์ˆ˜๋ฅผ ์ถฉ์กฑํ•˜์ง€ ๋ชปํ•˜๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ข…๋ฃŒํ•˜๊ณ  ์ถฉ์กฑํ•˜๋ฉด BootstrapContext์— CPU-CORE-X๋ฅผ ๋“ฑ๋กํ•œ๋‹ค.
ํ›„์— BootstrapContext์—์„œ CPU-CORE-X ๊ฐ’์„ ๊ฐ€์ ธ์™€์„œ Environment์— ๋“ฑ๋กํ•˜๊ณ  ApplicationContext์—์„œ ์ด ๊ฐ’์„ ์ฝ์„ ๊ฒƒ์ด๋‹ค.
*/
    @Override
    public void initialize( BootstrapRegistry registry ) {
        log.info( "<<< BootstrapInitializerCustom::initialize start." );
        int coreCnt = Runtime.getRuntime().availableProcessors();
        if ( coreCnt <= 2 ) {
            log.error( "<<< BootstrapInitializerCustom::initialize failed, cpu core must be > 2" );
            throw new RuntimeException( "BootstrapInitializerCustom initialize failed, cpu core must be > 2" );
        }

        log.info(  "<<< BootstrapInitializerCustom::initialize complete." );
        // BootstrapRegistry์— String ํƒ€์ž…์˜ CPU-CORE-X
        registry.register( String.class, context -> new String("CPU-CORE-" + coreCnt) );

    }
}
Java

BootstrapRegistryInitializer ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ๊ตฌํ˜„์ฒด๋‹ค. ApplicationContext๊ฐ€ ์ƒ์„ฑ๋˜๊ธฐ๋„ ์ „์ธ ์•„์ฃผ ์ดˆ๊ธฐ์— ์‹คํ–‰๋œ๋‹ค. cpu core ๊ฐœ์ˆ˜๋ฅผ ๊ฐ€์ ธ์™€์„œ 2๊ฐœ ์ดํ•˜์ธ ๊ฒฝ์šฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ข…๋ฃŒํ•œ๋‹ค. ์ฆ‰, ์ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ตฌ๋™ ์กฐ๊ฑด์€ cpu core ๊ฐœ์ˆ˜๊ฐ€ ์ตœ์†Œ 3๊ฐœ ์ด์ƒ์ด์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.
cpu core ๊ฐœ์ˆ˜๊ฐ€ ๋งŒ์กฑ๋œ๋‹ค๋ฉด BootstrapContext์— “CPU-CORE-<core ๊ฐœ์ˆ˜>” ๊ฐ’์„ ๋“ฑ๋กํ•œ๋‹ค.

ApplicationListenerCustom.java

@Slf4j
public class ApplicationListenerCustom implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
/*
Environment ์ค€๋น„๊ฐ€ ๋๋‚œ ๋’ค์— ๋ฐœ์ƒํ•˜๋Š” ์ด๋ฒคํŠธ๋ฅผ ํ›„ํ‚นํ•˜์—ฌ Environment์— BootstrapContext์— ๋“ฑ๋ก๋œ CPU-CORE-X ๊ฐ’์„ Environment์— ์ถ”๊ฐ€ํ•œ๋‹ค.
Environment์— ์ถ”๊ฐ€๋œ ๊ฐ’์„ ApplicationContext๊ฐ€ ์ƒ์„ฑ๋œ ์งํ›„ ํ›„ํ‚น ํด๋ž˜์Šค์—์„œ ๊บผ๋‚ด์™€ ๋กœ๊ทธ๋ฅผ ์ฐ์„ ์˜ˆ์ •์ด๋‹ค.
*/
    @Override
    public void onApplicationEvent( ApplicationEnvironmentPreparedEvent event ) {
        ConfigurableBootstrapContext bootstrapContext = event.getBootstrapContext();
        String cpuCoreInfo = bootstrapContext.get( String.class );
        log.info( "<<< ApplicationListenerCustom::get cpu core string from bootstrap context: {}", cpuCoreInfo );
        Map<String, Object> map = new HashMap<>();
        map.put( "app.system.cpu.core", cpuCoreInfo );
        event.getEnvironment().getPropertySources().addFirst( new MapPropertySource( "bootstrapProp", map ) );
        log.info( "<<< ApplicationListenerCustom::add property source to Environment: {}", map );
    }
}
Java

Environment ํ™˜๊ฒฝ ๊ตฌ์„ฑ์ด ์™„๋ฃŒ๋œ ์ดํ›„ ๋ฐœํ–‰๋˜๋Š” ApplicationEnvironmentPreparedEvent๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ์ •์˜ํ–ˆ๋‹ค. ApplicationEnvironmentPreparedEvent์—๋Š” BootstrapContext ๊ฐ์ฒด๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— BootstrapContext๋กœ๋ถ€ํ„ฐ CPU-CORE-<core ๊ฐœ์ˆ˜> ๊ฐ’์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.
BootstrapContext๋กœ๋ถ€ํ„ฐ ์–ป์€ ๊ฐ’์„ Environment์— ‘bootstrapProp’๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ PropertySource๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

ApplicationContextInitializerCustom.java

@Slf4j
public class ApplicationContextInitializerCustom implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    /*
    ApplicationListenerCustom์—์„œ ์ถ”๊ฐ€ํ•œ Environment์—์„œ 'bootstrapProp' ํ”„๋กœํผํ‹ฐ ์†Œ์Šค์—์„œ ์ถ”๊ฐ€ํ•œ ๊ฐ’์„ ๊ฐ€์ ธ์™€์„œ ์ถœ๋ ฅํ•œ๋‹ค.
     */
    @Override
    public void initialize( ConfigurableApplicationContext applicationContext ) {
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        PropertySource<?> bootstrapProp = environment.getPropertySources().get( "bootstrapProp" );
        Object cpuCoreProperty = bootstrapProp.getProperty( "app.system.cpu.core" );
        if (  cpuCoreProperty != null ) {
            log.info( "<<< ApplicationContextInitializerCustom::cpu core property from bootstrap context: {}", cpuCoreProperty );
        }
    }
}
Java

ApplicationContextInitializer<ConfigurableApplicationContext>๋ฅผ ๊ตฌํ˜„ํ•œ ์‚ฌ์šฉ์ž ์ •์˜ ๊ตฌํ˜„์ฒด๋‹ค. ApplicationContext๊ฐ€ ์ƒ์„ฑ๋œ ๋ฐ”๋กœ ์งํ›„์— ์‹คํ–‰๋œ๋‹ค.
ApplicationContext์— ์žˆ๋Š” Environment๋กœ๋ถ€ํ„ฐ ApplicationListenerCustom.java์—์„œ ์ถ”๊ฐ€ํ–ˆ๋˜ ‘bootstrapProp’ ์ด๋ฆ„์˜ PropertySource๋ฅผ ๊ฐ€์ ธ์™€์„œ CPU-CORE-<core ๊ฐœ์ˆ˜> ์ •๋ณด๋ฅผ ์–ป๋Š”๋‹ค.

SpringApplication์— BootstrapInitializer, ApplicationListener, ApplicationContextInitializer๋ฅผ ์ถ”๊ฐ€ ๋“ฑ๋กํ•œ๋‹ค.

@SpringBootApplication
public class SpringBootBootstrapApplication {

    public static void main( String[] args ) {
        SpringApplication springApplication = 
                new SpringApplication( SpringBootBootstrapApplication.class );
        springApplication.addBootstrapRegistryInitializer( new BootstrapInitializerCustom() );
        springApplication.addListeners( new ApplicationListenerCustom() );
        springApplication.addInitializers( new ApplicationContextInitializerCustom() );
        springApplication.run( args );
    }
}
Java

BootstrapInitializerCustom, ApplicationListenerCustom, ApplicationContextInitializerCustom์„ META-INF/spring.factories์— ๋“ฑ๋กํ•˜๊ฑฐ๋‚˜ ์œ„์™€ ๊ฐ™์ด ์ฝ”๋“œ ์ƒ์œผ๋กœ ์ถ”๊ฐ€ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๋‹ค.

์‹คํ–‰ ๊ฒฐ๊ณผ ๋กœ๊ทธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค. (ํŽธ์˜์ƒ ๋กœ๊ทธ ๋ผ์ธ ์ƒ์˜ ์•ž ๋ถ€๋ถ„์€ ๋ณด๊ธฐ์ข‹๊ฒŒ ์งค๋ž๋‹ค.)

BootstrapInitializerCustom -- <<< BootstrapInitializerCustom::initialize start.
BootstrapInitializerCustom -- <<< BootstrapInitializerCustom::initialize complete.
ApplicationListenerCustom      : <<< ApplicationListenerCustom::get cpu core string from bootstrap context: CPU-CORE-10
ApplicationListenerCustom      : <<< ApplicationListenerCustom::add property source to Environment: {app.system.cpu.core=CPU-CORE-10}

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v4.0.1)
 
ApplicationContextInitializerCustom : <<< ApplicationContextInitializerCustom::cpu core property from bootstrap context: CPU-CORE-10
Plaintext

๋‹จ๊ณ„ ๋ณ„๋กœ ์‹คํ–‰ ํ๋ฆ„์„ ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
๋ฐฐ๋„ˆ ์ถœ๋ ฅ ์ด์ „์— BootstrapInitializerCustom์ด ๊ฐ€์žฅ ๋จผ์ € ์‹คํ–‰๋˜์—ˆ๋‹ค. (3๋‹จ๊ณ„ – BootstrapContext ์ƒ์„ฑ)
์ดํ›„ Environment ๊ฐ์ฒด ์ƒ์„ฑ์ด ์™„๋ฃŒ๋œ ํ›„์— ApplicationListenerCustom์ด ์‹คํ–‰๋˜์—ˆ๋‹ค. (6๋‹จ๊ณ„ – Environment ์ค€๋น„)
๋ฐฐ๋„ˆ๊ฐ€ ์ถœ๋ ฅ๋˜์—ˆ๋‹ค. (7๋‹จ๊ณ„ – ๋ฐฐ๋„ˆ ์ถœ๋ ฅ)
์ดํ›„ ApplicationContextInitializerCustom์ด ์‹คํ–‰๋˜์—ˆ๋‹ค. (9๋‹จ๊ณ„ – ApplicationContext ์ค€๋น„ ๋‹จ๊ณ„)

์ด์™€ ๊ฐ™์ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ ๊ณผ์ •์˜ ํ๋ฆ„์„ ์•Œ๋ฉด ๋ถ€ํŠธ์ŠคํŠธ๋žฉ ๊ณผ์ •์—์„œ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š” ์ž‘์—…์ด ์žˆ์„ ๋•Œ ์œ ์—ฐํ•˜๊ฒŒ ๋Œ€์ฒ˜ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค.


Spring Boot ๋ถ€ํŠธ์ŠคํŠธ๋žฉ ๊ณผ์ •์€ ๋‹จ์ˆœํžˆ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“œ๋Š” ๊ณผ์ •์ด ์•„๋‹ˆ๋ผ ๋งค์šฐ ์ฒ ์ €ํ•˜๊ฒŒ ๊ณ„์‚ฐ๋œ ์ˆœ์„œ์— ๋”ฐ๋ผ ํ™˜๊ฒฝ์„ ๊ตฌ์ถ•ํ•ด๊ฐ€๋Š” ๊ณผ์ •์ด๋‹ค. ์ด 13๋‹จ๊ณ„๋ฅผ ์ดํ•ดํ•˜๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์„ฑ๋Šฅ์„ ํŠœ๋‹ํ•˜๊ฑฐ๋‚˜ ๊ตฌ๋™์‹œ ๋ฐœ์ƒํ•˜๋Š” ์—๋Ÿฌ๋ฅผ ํ›จ์”ฌ ์‰ฝ๊ฒŒ ๋””๋ฒ„๊น… ํ•  ์ˆ˜ ์žˆ๋‹ค.


๋จผ์ € ๋ณด๋ฉด ์ข‹์€ ํฌ์ŠคํŒ…
Spring Boot ์‹œ์ž‘ โ€“ SpringApplication ์ƒ์„ฑ๊ณผ ์ž๋™ ๊ฐ์ง€

๋‹ค์Œ์— ๋ณด๋ฉด ์ข‹์€ ํฌ์ŠคํŒ…
Spring Boot โ€“ Bean Initialization๊ณผ Event System