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;
}Java1๋จ๊ณ: 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();JavaApplicationContext๊ฐ ์์ฑ๋๊ธฐ ์ ๊น์ง ํ์ํ ์๋น์ค๋ค์ ์ ๊ณตํ๋ Bootstrap Context๋ฅผ ์์ฑํ๋ค.
BootstrapContext๋ ApplicationContext๊ฐ ์์ฑ๋๊ธฐ ์ ๋จ๊ณ์์ ํ์ํ ์๋น์ค๋ค์ ์ ๊ณตํ๋ ์์ ์ปจํ
์ด๋ ์ญํ ์ ํ๋ค.
BootstrapContext๊ฐ ํ์ํ ์ด์ ๋ ๋ค์๊ณผ ๊ฐ๋ค.
- ApplicationContext ์์ฑ์๋ ์๊ฐ์ด ๊ฑธ๋ฆผ(Bean ์ค์บ, ์๋ ๊ตฌ์ฑ๋ฑ)
- ํ์ง๋ง ApplicationContext ์์ฑ ๊ณผ์ ์์๋ ์ผ๋ถ ์๋น์ค๊ฐ ํ์ํจ
- ์: ํ๊ฒฝ ์ค์ ๋ก๋ฉ, ์ธ๋ถ ๊ตฌ์ฑ ์๋ฒ ์ฐ๊ฒฐ, ๋ณด์ ์ค์ ๋ฑ
BootstrapContext vs ApplicationContext
| ํน์ฑ | BootstrapContext | ApplicationContext |
| ์์ฑ ์์ | ์ ํ๋ฆฌ์ผ์ด์ ์์ ์งํ | ๋ถํธ์คํธ๋ฉ ๊ณผ์ ์ค๋ฐ |
| ์๋ช ์ฃผ๊ธฐ | ์งง์(ApplicationContext ์์ฑ ํ ์๋ฉธ) | ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฒด |
| ์ฉ๋ | ์ด๊ธฐ์ค์ , ์ธ๋ถ ์๋น์ค ์ฐ๊ฒฐ | ๋ชจ๋ Bean ๊ด๋ฆฌ |
| ์๋น์ค ์ | ์ ์ (ํ์์ ์ธ ๊ฒ๋ง) | ๋ง์ (์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์ ) |
| ์์กด์ฑ ์ฃผ์ | ์๋ ๋ฑ๋ก | ์๋ ์ฃผ์ |
๋ญ๊ณผ ๋ฌ๊ฑ ๋ฌธ์ ํด๊ฒฐ
๋ถํธ์คํธ๋ํ์์ ๊ณผ์ ์์ ๊ฐ์ฅ ํฅ๋ฏธ๋ก์ด ์์ ์ค ํ๋๊ฐ ๋ฐ๋ก BootstrapContext์ด๋ค.
ApplicationContext๋ฅผ ๋ง๋ค๊ธฐ ์ํด์๋ ์ค์ (Configuration)์ด ํ์ํ๋ค. ํ์ง๋ง ์ค์ ์ ๊ฐ์ ธ์ค๊ธฐ ์ํด์ ์ธ๋ถ ์๋น์ค(์: Spring Cloud Config)์ ์ฐ๊ฒฐํ๋ ค๋ฉด ๋ ๋ค๋ฅธ ๊ฐ์ฒด๊ฐ ํ์ํ๋ค. ์ด๋ฌํ ์ํ ์์กด์ฑ์ ๋๊ธฐ ์ํด Spring Boot๋ BootstrapContext ์ฅ์น๋ฅผ ๋ง๋ จํ๊ณ ์ด๋ ApplicationContext ์์ฑ์ ํ์ํ ์ต์ํ์ ์๋น์ค๋ค์ ๋ฏธ๋ฆฌ ์ค๋นํด๋๋ ์ญํ ์ ํ๋ค.
4๋จ๊ณ: ํค๋๋ฆฌ์ค ๋ชจ๋ ์ค์
configureHeadlessProperty();JavaGUI๊ฐ ์๋ ์๋ฒ ํ๊ฒฝ์์ ์คํ๋จ์ ์์คํ ์ ์๋ฆฌ๋ ์ญํ ์ ํ๋ค. ์ด ๋ฉ์๋๋ ๋ด๋ถ์ ์ผ๋ก 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);JavaSpring Boot์ ์์ ๋ฐฐ๋๋ฅผ ์ฝ์์ ์ถ๋ ฅํ๋ค. spring.main.banner-mode๋ก ์ ์ด๊ฐ ๊ฐ๋ฅํ๋ค.
8๋จ๊ณ: ApplicationContext ์์ฑ
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);Java์น ์ ํ๋ฆฌ์ผ์ด์ ํ์ ์ ๋ฐ๋ผ ์ ์ ํ ApplicationContext ๊ตฌํ์ฒด๋ฅผ ์์ฑํ๊ณ ApplicationStartup ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ค.
| ์ ํ๋ฆฌ์ผ์ด์ ํ์ | ApplicationContext ๊ตฌํ์ฒด | ํน์ง |
| SERVLET | AnnotationConfigServletWebServerApplicationContext | ํฐ์บฃ ๋ด์ฅ ์๋ธ๋ฆฟ ์๋ฒ ๊ด๋ฆฌ |
| REACTIVE | AnnotationConfigReactiveWebServerApplicationContext | ๋คํฐ ๊ธฐ๋ฐ ๋ฆฌ์กํฐ๋ธ ์๋ฒ ๋ฐ ๋น๋๊ธฐ ์ฒ๋ฆฌ |
| NONE | AnnotationConfigApplicationContext | ์น ์๋ฒ ์๋ ๊ฒฝ๋ ๊ตฌ์กฐ |
SERVLET ํ์ ์ ๊ฒฝ์ฐ ์ปจํ ์คํธ์ onRefresh() ๋จ๊ณ์์ createWebServer()๋ฅผ ํธ์ถํ์ฌ ๋ด์ฅ ํฐ์บฃ ์๋ฒ๋ฅผ ์ค์ ๊ธฐ๋ํ๋ค.
9๋จ๊ณ: ApplicationContext ์ค๋น
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);JavaApplicationContext๋ฅผ ์ด๊ธฐํํ๊ณ Bean ์ ์๋ฅผ ๋ฑ๋กํ๋ค. (Bean์ ๋ฑ๋กํ๋ ๊ฒ์ด ์๋ Bean ์์ฑ์ ์ํ ์ ์๋ฅผ ๋ก๋ํ๋ ๊ฒ์ด๋ค)
์ด ๋จ๊ณ์์๋ ํต์ฌ์ ์ธ ์ฌ๋ฌ ๋จ๊ณ๋ฅผ ํฌํจํ๋ค.
๋ค์์ prepareContext() ๋ด์์ ์คํ๋๋ ๋์๋ค์ด๋ค.
ApplicationContext์ Environment ์ฃผ์
context.setEnvironment(environment);JavaApplicationContextInitializer ์คํ
applyInitializers(context);Java์ฌ์ฉ์ ์ ์ ApplicationContextInitializer๋ฅผ ์ถ๊ฐํ๋ค๋ฉด ์ด ๋จ๊ณ์์ ์ฌ์ฉ์ ์ ์ ApplicationContextInitializer๊ฐ ์คํ๋๋ค.
์ปจํ ์คํธ ์ค๋น ์๋ฃ ์ด๋ฒคํธ ๋ฐํ
listeners.contextPrepared(context);JavaSpringApplication ์ธ์คํด์ค์ ๋ฑ๋ก๋ ๋ฆฌ์ค๋๋ค์๊ฒ ApplicationContextInitializedEvent๋ฅผ ์ ๋ฌํ๋ค.
BootstrapContext ์ข ๋ฃ
bootstrapContext.close(context);Java์ปจํ ์คํธ ๋ก๋ ์๋ฃ ์ด๋ฒคํธ ๋ฐํ
listeners.contextLoaded(context);JavaSpringApplication ์ธ์คํด์ค์ ๋ฑ๋ก๋์ด ์๋ ๋ฆฌ์ค๋๋ค ์ค์์ ApplicationContextAware ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ ๋ฆฌ์ค๋๋ฅผ ์ฐพ์์ ๋ฐฉ๊ธ ๋ก๋๋ ApplicationContext ๊ฐ์ฒด๋ฅผ ์ ๋ฌํ๊ณ ApplicationPreparedEvent๋ฅผ ๋ฐํํ๋ค. ์ด ์ด๋ฒคํธ๋ Bean์ด ์ค์ ๋ก ์์ฑ๋๊ธฐ ์ ์ ๋ง์ง๋ง์ผ๋ก ์ค์ ์ ์กฐ์ํด์ผ ํ ๊ธฐ๋ฅ๋ค์ด ์์ ํ๋ค.
ApplicationListener<ApplicationPreparedEvent> ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ ์ฌ์ฉ์ ์ ์ ๊ตฌํ์ฒด๋ฅผ SpringApplication ์ธ์คํด์ค์ addListener๋ฅผ ํตํด์ ๋ฑ๋กํ์ฌ ApplicationPreparedEvent๋ฅผ ๋ฐ์์ ์ฒ๋ฆฌํ ์ ์๋ค.
10๋จ๊ณ: ApplicationContext refresh
์ด ๋จ๊ณ์์ ๋๋์ด Bean์ ์์ฑํ๊ณ ์์กด์ฑ์ ์ฃผ์ ํ๋ฉฐ ์น ์๋ฒ๋ฅผ ์์ํ๋ค.
refreshContext(context);Java์ด ๋จ๊ณ๊ฐ Spring Boot ์ ํ๋ฆฌ์ผ์ด์ ๊ธฐ๋ ๊ณผ์ ์์ ๊ฐ์ฅ ํต์ฌ์ ์ธ ๋จ๊ณ๋ผ๊ณ ํ ์ ์๋ค.
- BeanFactory ์ค๋น ๋ฐ PostProcessor ์คํ
- ApplicationContext ๋ด๋ถ์ BeanFactory๋ฅผ ์ค๋นํ๋ค.
- @Configuration ํด๋์ค๋ฅผ ๋ถ์ํ์ฌ ์ด๋ค Bean๋ค์ ์์ฑํด์ผ ํ ์ง ์ต์ข ๊ฒฐ์ ํ๋ค.
- PropertySourcesPlaceholderConfigurer ๊ฐ์ ํ๋ก์ธ์๊ฐ ๋์ํ์ฌ Bean ์ค์ ์ ํฌํจ๋ ${…} ๊ฐ๋ค์ ์ค์ ํ๊ฒฝ ๋ณ์๋ก ์นํํ๋ค.
- Bean ํ์ฒ๋ฆฌ๊ธฐ ๋ฑ๋ก (registerBeanPostProcessors)
- Bean์ด ์์ฑ๋๊ธฐ ์ ๊ณผ ํ์ ๊ฐ์ ํ์ฌ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ฑฐ๋(AOP) ์ถ๊ฐ ์ค์ ์ ์ฒ๋ฆฌํ BeanPostProcessor๋ค์ ๋จผ์ ์์ฑํ์ฌ ๋ฑ๋กํ๋ค.
- BeanPostProcessors ์ธํฐํ์ด์ค์ ๋ํ ์ฌ์ฉ์ ์ ์ ๊ตฌํ์ฒด ํด๋์ค๋ฅผ ๋ง๋ค์ด์ ํน์ Bean์ ๋ํ ํน์ ์ฒ๋ฆฌ๋ฅผ ํ๊ฑฐ๋ AOP๋ฅผ ์ ์ฉํ ์๋ก์ด Bean์ ๋ฑ๋กํ ์๋ ์๋ค.
- ๋ด์ฅ ์น์๋ฒ ๊ธฐ๋ (onRefresh)
- ์น ์ ํ๋ฆฌ์ผ์ด์ (SERVLET, REACTIVE) ํ์ ์ธ ๊ฒฝ์ฐ Tomcat, Jetty, Netty์ ๊ฐ์ ๋ด์ฅ ์น ์๋ฒ๋ฅผ ๊ธฐ๋ํ๋ค.
- ๋ชจ๋ ์ฑ๊ธํค Bean์ ์ธ์คํด์คํ
- ๊ฐ์ฅ ๋ง์ ์๊ฐ์ด ์์๋๋ ๊ตฌ๊ฐ์ด๋ค.
- ์ ์๋ ๋ชจ๋ ์ฑ๊ธํค Bean์ ์ค์ ๋ฉ๋ชจ๋ฆฌ์ ๋ก๋ํ๋ค. (Instantiation)
- Bean๋ค ์ฌ์ด์ ์์กด์ฑ ์ฃผ์ ์ด ์ด๋ฃจ์ด์ง๋ค.
- SpringApplication ์ธ์คํด์ค์์ LazyInitialization ์์ฑ์ด false(๊ธฐ๋ณธ๊ฐ)์ด๋ฉด ๋ชจ๋ Bean์ด ์ด ๋จ๊ณ์์ ์ฆ์ ์์ฑ๋๋ค.
- refresh ์๋ฃ ๋ฐ ์ด๋ฒคํธ ๋ฐํ
- ContextRefreshedEvent๋ฅผ ๋ฐํํ์ฌ ApplicationContext๊ฐ ์์ ํ ๊ฐ๋ ๋์์์ ์๋ฆฐ๋ค.
BeanPostProcessor ์ธํฐํ์ด์ค
BeanPostProcessor ์ธํฐํ์ด์ค๋ ๋๊ฐ์ง ํต์ฌ ๋ฉ์๋๋ฅผ ์ ๊ณตํ๋ค.
postProcessBeforeInitialization: ๋น ๊ฐ์ฒด๊ฐ ์์ฑ๋๊ณ ์์กด์ฑ ์ฃผ์ ์ด ์๋ฃ๋ ํ @PostConstruct๋ afterPropertiesSet์ด ํธ์ถ๋๊ธฐ ์ง์ ์ ์คํ๋๋ค.
postProcessAfterInitialization: ์ด๊ธฐํ ๋ฉ์๋(@PostConstruct๋ฑ)๊ฐ ์คํ๋ ์งํ์ ์คํ๋๋ค. ์ฃผ๋ก ํ๋ก์ ๊ฐ์ฒด๋ก ๊ฐ์ธ๊ฑฐ๋(AOP) ์ต์ข ๊ฒ์ฆ์ ํ ๋ ์ฌ์ฉํ๋ค.
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);JavaApplicationRunner์ CommandLineRunner ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ Bean๋ค์ ์ฐพ์ ์คํํ๋ค.
13๋จ๊ณ: ์ค๋น ์๋ฃ ์ด๋ฒคํธ ๋ฐํ
if (context.isRunning()) {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
}JavaApplicationReadyEvent๋ฅผ ๋ฐํํ์ฌ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์์ ํ ์ค๋น๋์์์ ์๋ฆฐ๋ค.
์ ํ๋ฆฌ์ผ์ด์ ๋ถํธ์คํธ๋ฉ ๊ณผ์ ์์ ์ด๋ฒคํธ ์ฒ๋ฆฌ ์ํ
์ ํ๋ฆฌ์ผ์ด์ ๋ถํธ์คํธ๋ฉ ๊ณผ์ ์์ ์ฌ์ฉ์ ์ ์ 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 ๊ฐ์> ๊ฐ์ ๋ก๊น
PlaintextBootstrapInitializerCustom.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) );
}
}JavaBootstrapRegistryInitializer ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ ๊ตฌํ์ฒด๋ค. 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 );
}
}JavaEnvironment ํ๊ฒฝ ๊ตฌ์ฑ์ด ์๋ฃ๋ ์ดํ ๋ฐํ๋๋ 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 );
}
}
}JavaApplicationContextInitializer<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 );
}
}JavaBootstrapInitializerCustom, 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-10Plaintext๋จ๊ณ ๋ณ๋ก ์คํ ํ๋ฆ์ ๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
๋ฐฐ๋ ์ถ๋ ฅ ์ด์ ์ BootstrapInitializerCustom์ด ๊ฐ์ฅ ๋จผ์ ์คํ๋์๋ค. (3๋จ๊ณ – BootstrapContext ์์ฑ)
์ดํ Environment ๊ฐ์ฒด ์์ฑ์ด ์๋ฃ๋ ํ์ ApplicationListenerCustom์ด ์คํ๋์๋ค. (6๋จ๊ณ – Environment ์ค๋น)
๋ฐฐ๋๊ฐ ์ถ๋ ฅ๋์๋ค. (7๋จ๊ณ – ๋ฐฐ๋ ์ถ๋ ฅ)
์ดํ ApplicationContextInitializerCustom์ด ์คํ๋์๋ค. (9๋จ๊ณ – ApplicationContext ์ค๋น ๋จ๊ณ)
์ด์ ๊ฐ์ด ์ ํ๋ฆฌ์ผ์ด์ ๋ถํธ์คํธ๋ฉ ๊ณผ์ ์ ํ๋ฆ์ ์๋ฉด ๋ถํธ์คํธ๋ฉ ๊ณผ์ ์์ ์ฒ๋ฆฌํด์ผ ํ๋ ์์ ์ด ์์ ๋ ์ ์ฐํ๊ฒ ๋์ฒํ ์ ์์ ๊ฒ ๊ฐ๋ค.
Spring Boot ๋ถํธ์คํธ๋ฉ ๊ณผ์ ์ ๋จ์ํ ๊ฐ์ฒด๋ฅผ ๋ง๋๋ ๊ณผ์ ์ด ์๋๋ผ ๋งค์ฐ ์ฒ ์ ํ๊ฒ ๊ณ์ฐ๋ ์์์ ๋ฐ๋ผ ํ๊ฒฝ์ ๊ตฌ์ถํด๊ฐ๋ ๊ณผ์ ์ด๋ค. ์ด 13๋จ๊ณ๋ฅผ ์ดํดํ๋ฉด ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ฑ๋ฅ์ ํ๋ํ๊ฑฐ๋ ๊ตฌ๋์ ๋ฐ์ํ๋ ์๋ฌ๋ฅผ ํจ์ฌ ์ฝ๊ฒ ๋๋ฒ๊น ํ ์ ์๋ค.
๋จผ์ ๋ณด๋ฉด ์ข์ ํฌ์คํ
Spring Boot ์์ โ SpringApplication ์์ฑ๊ณผ ์๋ ๊ฐ์ง
๋ค์์ ๋ณด๋ฉด ์ข์ ํฌ์คํ
Spring Boot โ Bean Initialization๊ณผ Event System
