[Spring Boot ์‹œ์ž‘๊ณผ์ •] 1. SpringApplication ์ƒ์„ฑ๊ณผ ์ž๋™ ๊ฐ์ง€

Spring Boot ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•  ๋•Œ ์šฐ๋ฆฌ๊ฐ€ ๊ฐ€์žฅ ๋จผ์ € ๋งˆ์ฃผํ•˜๋Š” ์ฝ”๋“œ๋Š” @SpringBootApplication ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ ํด๋ž˜์Šค์™€ ๊ทธ ์•ˆ์˜ main ๋ฉ”์„œ๋“œ์ผ ๊ฒƒ์ด๋‹ค.

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

๋ช‡ ์ค„ ์•ˆ๋˜๋Š” ๋งค์šฐ ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ์ง€๋งŒ SpringApplication.run() ํ˜ธ์ถœ ๋’ค์—๋Š” ์ˆ˜์‹ญ ๊ฐœ์˜ ํด๋ž˜์Šค๊ฐ€ ํ˜‘๋ ฅํ•˜์—ฌ ๋ณต์žกํ•œ ์ดˆ๊ธฐํ™” ๊ณผ์ •์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. Spring Boot๋Š” ์ด๋Ÿฌํ•œ ๋ณต์žก์„ฑ์„ ์ˆจ๊ธฐ๊ณ  ๊ฐœ๋ฐœ์ž์—๊ฒŒ ๋‹จ์ˆœํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•˜์ง€๋งŒ ๋‚ด๋ถ€ ๋™์ž‘์„ ์ดํ•ด ํ•˜๋ฉด ๋” ํšจ๊ณผ์ ์œผ๋กœ Spring Boot๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” SpringApplication ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ ๋‚ด๋ถ€์ ์œผ๋กœ ์–ด๋–ค ๋™์ž‘๋“ค์ด ์ด๋ฃจ์–ด์ง€๋Š”์ง€ ์ •๋ฆฌํ•ด ๋ณด๊ณ ์ž ํ•œ๋‹ค.

SpringApplication์˜ ์—ญํ• 

SpringApplication ํด๋ž˜์Šค๋Š” Spring Boot ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ถ€ํŠธ์ŠคํŠธ๋ž˜ํ•‘์„ ๋‹ด๋‹นํ•˜๋Š” ํ•ต์‹ฌ ํด๋ž˜์Šค๋‹ค. ์ด ํด๋ž˜์Šค๋Š” ๋‹จ์ˆœํžˆ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ์„ ๋„˜์–ด์„œ ์ ์ ˆํ•œ ApplicationContext๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ํ™˜๊ฒฝ์„ ๊ตฌ์„ฑํ•˜๊ณ  ๋‹ค์–‘ํ•œ ๋ฆฌ์Šค๋„ˆ๋“ค์„ ๊ด€๋ฆฌํ•˜๋Š” ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

SpringApplication ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ ์ˆ˜ํ–‰๋˜๋Š” ์ดˆ๊ธฐํ™” ์ž‘์—…์„ ์‚ดํŽด๋ณด์ž.
SpringApplication.run(MyApplication.class, args); ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๋ฉด ๋‚ด๋ถ€์ ์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ๋ฆ„์œผ๋กœ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋œ๋‹ค.

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
	return run(new Class<?>[] { primarySource }, args);
}
	
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
	return new SpringApplication(primarySources).run(args);
}

// SpringApplication.run() ์‹คํ–‰์‹œ ํ˜ธ์ถœ๋˜๋Š” ์ƒ์„ฑ์ž
public SpringApplication(Class<?>... primarySources) {
	this(null, primarySources);
}

// SpringApplication.run() ์‹คํ–‰์‹œ ์ตœ์ข…์ ์œผ๋กœ ํ˜ธ์ถœ๋˜๋Š” ์ƒ์„ฑ์ž
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  // resourceLoader ์ธ์Šคํ„ด์Šค ์„ค์ •
	this.resourceLoader = resourceLoader;
	Assert.notNull(primarySources, "PrimarySources must not be null");
	// ๋ฉ”์ธ ํด๋ž˜์Šค ์„ค์ •
	this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
	// classPath๋ฅผ ํ†ตํ•œ WebApplicationType ์ž๋™ ๊ฐ์ง€
	this.webApplicationType = WebApplicationType.deduceFromClasspath();
	// BootstrapRegistryInitializer ํด๋ž˜์Šค ๋กœ๋”ฉ
	this.bootstrapRegistryInitializers = new ArrayList<>(
			getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
	// ApplicationContextInitializer ํด๋ž˜์Šค ๋กœ๋”ฉ
	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
	// ApplicationListener ํด๋ž˜์Šค ๋กœ๋”ฉ
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
	this.mainApplicationClass = deduceMainApplicationClass();
}
Java

SpringApplication.run() ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด ๋‚ด๋ถ€์ ์œผ๋กœ new SpringApplication(..)์„ ํ†ตํ•ด์„œ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.
์ด ๋•Œ ์ƒ์„ฑ์ž์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ•ต์‹ฌ ์ดˆ๊ธฐํ™” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

  1. ResourceLoader๋ฐ ๊ธฐ๋ณธ ์†Œ์Šค ์„ค์ •
    • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‚ฌ์šฉํ•  ๋ฆฌ์†Œ์Šค๋ฅผ ์ฝ์–ด์˜ฌ ๋กœ๋”๋ฅผ ์„ค์ •ํ•˜๊ณ  @SpringBootApplication์ด ์„ ์–ธ๋œ ๋ฉ”์ธ ํด๋ž˜์Šค๋ฅผ ์ €์žฅํ•˜์—ฌ ์ด ํ›„ ๋นˆ ์Šค์บ๋‹์˜ ๊ธฐ์ ์œผ๋กœ ์‚ผ๋Š”๋‹ค.
    • ๊ธฐ๋ณธ์ ์œผ๋กœ SpringApplication.run(…)์„ ํ˜ธ์ถœํ•œ ๊ฒฝ์šฐ์—๋Š” ResourceLoader๋Š” null์ด ์ „๋‹ฌ๋œ๋‹ค. ํ›„์— ๋‚ด๋ถ€์ ์œผ๋กœ DefaultResourceLoader๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์‚ฌ์šฉํ•œ๋‹ค.
  2. WebApplicationType ์ž๋™ ๊ฐ์ง€
    • Spring Boot์˜ ๊ฐ€์žฅ ํฐ ์žฅ์ ์€ ์ž๋™ ์„ค์ •์ด๋‹ค. ๊ฐœ๋ฐœ์ž๊ฐ€ ๋ณ„๋„์˜ ์„ค์ •์„ ํ•˜์ง€ ์•Š์•„๋„ Spring Boot๋Š” sspath๋ฅผ ๋ถ„์„ํ•ด ํ˜„์žฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํƒ€์ž…์„ ๊ฒฐ์ •ํ•œ๋‹ค.
      • SERVLET: DispatcherServlet ํด๋ž˜์Šค๊ฐ€ ํด๋ž˜์ŠคํŒจ์Šค์— ์žˆ๋‹ค๋ฉด ์ผ๋ฐ˜์ ์ธ Spring MVC ์›น ์•ฑ์œผ๋กœ ๊ตฌ๋™ํ•œ๋‹ค.
      • REACTIVE: DispatcherHandler๊ฐ€ ์žˆ๊ณ  ์„œ๋ธ”๋ฆฟ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์—†๋‹ค๋ฉด WebFlux ๊ธฐ๋ฐ˜์˜ ๋ฆฌ์•กํ‹ฐ๋ธŒ ์•ฑ์œผ๋กœ ๊ตฌ๋™ํ•œ๋‹ค.
      • NONE: ์œ„ ํด๋ž˜์Šค๋“ค์ด ์—†๋‹ค๋ฉด ์›น ์„œ๋ฒ„๊ฐ€ ํ•„์š”์—†๋Š” ์ผ๋ฐ˜ ์ž๋ฐ” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์œผ๋กœ ๊ตฌ๋™๋œ๋‹ค.
  3. ์ดˆ๊ธฐํ™” ๊ด€๋ จ ์ปดํฌ๋„ŒํŠธ ๋กœ๋“œ
    • BootstrapRegistryInitializer
      • META-INF/spring.factories ์—์„œ BootstrapRegistryInitializer ํƒ€์ž…์˜ ๊ตฌํ˜„์ฒด๋“ค์„ ์ฐพ์•„์„œ ๋กœ๋”ฉํ•œ๋‹ค. ํ•ด๋‹น ๊ตฌํ˜„์ฒด๋“ค์€ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์ดˆ๊ธฐํ™”๋ฅผ ์œ„ํ•œ ์ปดํฌ๋„ŒํŠธ๋“ค์ด๋‹ค.
    • ApplicationContextInitializer
      • META-INF/spring.factories ์—์„œ ApplicationContextInitializer ํƒ€์ž…์˜ ๊ตฌํ˜„์ฒด๋“ค์„ ์ฐพ์•„์„œ ๋กœ๋”ฉํ•œ๋‹ค. ํ•ด๋‹น ๊ตฌํ˜„์ฒด๋“ค์€ ApplicationContext ์ดˆ๊ธฐํ™”๋ฅผ ์œ„ํ•œ ์ปดํฌ๋„ŒํŠธ๋“ค์„ ๋กœ๋“œํ•œ๋‹ค.
    • ApplicationListener
      • META-INF/spring.factories ์—์„œ ApplicationListener ํƒ€์ž…์˜ ๊ตฌํ˜„์ฒด๋“ค์„ ์ฐพ์•„์„œ ๋กœ๋”ฉํ•œ๋‹ค. ํ•ด๋‹น ๊ตฌํ˜„์ฒด๋“ค์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ด๋ฒคํŠธ๋ฅผ ์ˆ˜์‹ ํ•  ๋ฆฌ์Šค๋„ˆ ์—ญํ• ์„ ํ•œ๋‹ค.

๋‹ค์Œ์€ spring boot 3.2.1 ๋ฒ„์ „์˜ spring-boot-auto-configure์˜ spring.factories ํŒŒ์ผ์˜ ์ผ๋ถ€๋‹ค.

# ApplicationContext Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
Java

WebApplicationType ์ž๋™ ๊ฐ์ง€ ๋ฉ”์นด๋‹ˆ์ฆ˜ ๋•๋ถ„์— spring-boot-starter-web ์˜์กด์„ฑ๋งŒ ์ถ”๊ฐ€ํ•ด๋„ ์ž๋™์œผ๋กœ ๋‚ด์žฅ๋œ ํ†ฐ์บฃ์„ ํ†ตํ•ด ์›น ์„œ๋ฒ„๊ฐ€ ์‹คํ–‰๋œ๋‹ค.

META-INF/spring.factories ํŒŒ์ผ์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์˜์กด์„ฑ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์žˆ๋Š” ํŒŒ์ผ์„ ์ฐพ๋Š”๋‹ค.

WebApplicationType ์ž๋™ ๊ฐ์ง€

์•ž์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด Spring Boot๋Š” ํด๋ž˜์ŠคํŒจ์Šค์— ์กด์žฌํ•˜๋Š” ํด๋ž˜์Šค๋“ค์„ ๋ถ„์„ํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํƒ€์ž…์„ ์ž๋™์œผ๋กœ ๊ฒฐ์ •ํ•œ๋‹ค.
์ž๋™ ๊ฐ์ง€๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด์ž.

// WebApplicationType ํด๋ž˜์Šค ๋‚ด๋ถ€์˜ ์ƒ์ˆ˜๋“ค
// Servlet ๊ธฐ๋ฐ˜ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ž„์„ ํŒ๋ณ„ํ•˜๊ธฐ ์œ„ํ•œ ์ตœ์†Œ ์กฐ๊ฑด
// ๋‘˜ ์ค‘์— ํ•˜๋‚˜๋ผ๋„ ์—†์œผ๋ฉด SERVLET ์›น์ด ์•„๋‹˜
private static final String[] SERVLET_INDICATOR_CLASSES = {
    "javax.servlet.Servlet",
    "org.springframework.web.context.ConfigurableWebApplicationContext"
};

// Spring MVC(WebMVC) ์กด์žฌ ์—ฌ๋ถ€ ํŒ๋ณ„ ํด๋ž˜์Šค
private static final String WEBMVC_INDICATOR_CLASS =
    "org.springframework.web.servlet.DispatcherServlet";

// Spring WebFlux(๋ฆฌ์•กํ‹ฐ๋ธŒ ์›น) ์กด์žฌ ์—ฌ๋ถ€
private static final String WEBFLUX_INDICATOR_CLASS =
    "org.springframework.web.reactive.DispatcherHandler";

// Jersey(JAX-RS) ๊ธฐ๋ฐ˜ Servlet ์กด์žฌ ์—ฌ๋ถ€
private static final String JERSEY_INDICATOR_CLASS =
    "org.glassfish.jersey.servlet.ServletContainer";

static WebApplicationType deduceFromClasspath() {
    // Reactive ํŒ๋ณ„, WebFlux ๋‹จ๋…์ธ ๊ฒฝ์šฐ์—๋งŒ REACTIVE
    // WebFlux๋Š” Servlet ๊ธฐ๋ฐ˜๊ณผ ๋™์‹œ์— ์กด์žฌํ•  ์ˆ˜ ์žˆ์Œ (๊ธฐ๋ณธ์€ Servlet)
    if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
        && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
        && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
        return WebApplicationType.REACTIVE;
    }
    for (String className : SERVLET_INDICATOR_CLASSES) {
        if (!ClassUtils.isPresent(className, null)) {
            return WebApplicationType.NONE;
        }
    }
    return WebApplicationType.SERVLET;
}
Java

์œ„ ์ฝ”๋“œ๋Š” ํด๋ž˜์ŠคํŒจ์Šค์— ์–ด๋–ค ์›น ๊ธฐ์ˆ ์ด ์กด์žฌํ•˜๋Š”์ง€๋กœ ํƒ€์ž…์„ ํŒ๋‹จํ•œ๋‹ค.
WebFlux(๋ฆฌ์•กํ‹ฐ๋ธŒ์›น)์˜ ๊ฒฝ์šฐ Servlet๊ณผ ๋™์‹œ์— ์กด์žฌํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ ๋™์‹œ์— ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ ํƒ€์ž…์€ SERVLET๊ฐ€ ๋œ๋‹ค.

  1. SERVLET: ์ „ํ†ต์ ์ธ ์„œ๋ธ”๋ฆฟ ๊ธฐ๋ฐ˜ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜
    • spring-boot-starter-web ์˜์กด์„ฑ์ด ์žˆ์„ ๋•Œ
    • DispatcherServlet ๊ธฐ๋ฐ˜
  2. REACTIVE: ๋ฆฌ์•กํ‹ฐ๋ธŒ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜
    • spring-boot-starter-webflux ์˜์กด์„ฑ์ด ์žˆ์„ ๋•Œ
    • Spring WebFlux ๊ธฐ๋ฐ˜
  3. NONE: ์›น์ด ์•„๋‹Œ ์ผ๋ฐ˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜
    • ์›น ๊ด€๋ จ ์˜์กด์„ฑ์ด ์—†์„ ๋•Œ
    • ๋ฐฐ์น˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜, CLI ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋“ฑ

ApplicationContextInitializer์™€ ApplicationListener ๋“ฑ๋ก

Spring Boot๋Š” META-INF/spring.factories ํŒŒ์ผ์„ ํ†ตํ•ด ๋‹ค์–‘ํ•œ ์ดˆ๊ธฐํ™” ์ปดํฌ๋„ŒํŠธ๋“ค์„ ์ž๋™์œผ๋กœ ๋“ฑ๋กํ•œ๋‹ค.

private <T> List<T> getSpringFactoriesInstances(Class<T> type) {
    return getSpringFactoriesInstances(type, null);
}

private <T> List<T> getSpringFactoriesInstances(Class<T> type, ArgumentResolver argumentResolver) {
    return SpringFactoriesLoader.forDefaultResourceLocation(getClassLoader()).load(type, argumentResolver);
}
Java

Spring Boot 3.X์˜ SpringFactoriesLoader ๋ณ€ํ™”

Spring Boot 3.X์—์„œ๋Š” SpringFactoriesLoader์˜ ์‚ฌ์šฉ ๋ฐฉ์‹์ด ๊ฐœ์„ ๋˜์—ˆ๋‹ค.

  • ๊ธฐ์กด ๋ฐฉ์‹(2.X): SpringFactoriesLoader.loadFactoryNames() + ์ˆ˜๋™ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
  • ์ƒˆ๋กœ์šด ๋ฐฉ์‹(3.X): SpringFactoriesLoader.forDefaultResourceLocation().load() ์ง์ ‘ ํ˜ธ์ถœ

์ฃผ์š” ๊ฐœ์„  ์‚ฌํ•ญ

  1. fluent API ์Šคํƒ€์ผ: forDefaultResourceLocation(classLoader).load(type, argumentResolver) ํ˜•ํƒœ๋กœ ๋ฉ”์„œ๋“œ ์ฒด์ด๋‹์„ ์‚ฌ์šฉํ•œ๋‹ค.
  2. ArgumentResolver ์ง€์›: ์ƒ์„ฑ์ž ํŒŒ๋ผ๋ฏธํ„ฐ ํ•ด๊ฒฐ์„ ์œ„ํ•œ ArgumentResolver ์ถ”๊ฐ€ ์ง€์›ํ•œ๋‹ค.
  3. ํƒ€์ž… ์•ˆ์ •์„ฑ ๊ฐ•ํ™”: ์ œ๋„ค๋ฆญ์„ ํ†ตํ•œ ์ปดํŒŒ์ผ ํƒ€์ž„ ํƒ€์ž… ์ฒดํฌ
  4. ์„ฑ๋Šฅ ์ตœ์ ํ™”: ๋‚ด๋ถ€์ ์œผ๋กœ ์บ์‹ฑ๊ณผ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ ๊ณผ์ •์ด ์ตœ์ ํ™” ๋˜์—ˆ๋‹ค.

ApplicationContextInitializer์˜ ์—ญํ• 

  • ApplicationContext๊ฐ€ refresh ๋˜๊ธฐ ์ „์— ์ถ”๊ฐ€์ ์ธ ์ดˆ๊ธฐํ™” ์ž‘์—… ์ˆ˜ํ–‰
  • PropertySource ์ถ”๊ฐ€, ํ”„๋กœํŒŒ์ผ ํ™œ์„ฑํ™”, Bean ์ •์˜ ํ›„์ฒ˜๋ฆฌ ๋“ฑ
  • ์˜ˆ: ConfigurationWarningsApplicationContextInitializer, ContextIdApplicationContextInitializer

ApplicationListener์˜ ์—ญํ• 

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ๊ณผ์ •์˜ ๋‹ค์–‘ํ•œ ์ด๋ฒคํŠธ๋ฅผ ์ˆ˜์‹ ํ•˜์—ฌ ๋กœ๊น…, ๋ชจ๋‹ˆํ„ฐ๋ง, ์ปค์Šคํ…€ ์ดˆ๊ธฐํ™” ๋กœ์ง ์‹คํ–‰
  • ์˜ˆ: LoggingApplicationListener, BackgroundPreinitializer, DelegatingApplicationListener

BootstrapRegistryInitializer์˜ ์—ญํ• 

  • ApplicationContext ์ƒ์„ฑ ์ด์ „ ๋‹จ๊ณ„์—์„œ ํ•„์š”ํ•œ ์„œ๋น„์Šค๋“ค์„ BootstrapRegistry์— ๋“ฑ๋ก
  • ์ดˆ๊ธฐ ์„ค์ •์ด๋‚˜ ์™ธ๋ถ€ ์‹œ์Šคํ…œ ์—ฐ๊ฒฐ๋“ฑ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ ๋‹จ๊ณ„์—์„œ ํ•„์š”ํ•œ ์ž‘์—… ์ˆ˜ํ–‰

SpringApplication ์ฃผ์š” public ๋ฉ”์„œ๋“œ

SpringApplication.run() ์ •์  ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ๋กœ ๊ธฐ๋ณธ์ ์ธ ์…‹ํŒ…์„ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ SpringApplication ์ธ์Šคํ„ด์Šค๋ฅผ ์ง์ ‘ ์ƒ์„ฑํ•˜์—ฌ ๋‹ค์–‘ํ•œ public ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ๊ตฌ๋™ ํ™˜๊ฒฝ์„ ์„ธ๋ฐ€ํ•˜๊ฒŒ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ฉ”์„œ๋“œ์„ค๋ช…๋””ํดํŠธ
setWebApplicationTypeClasspath ๊ธฐ๋ฐ˜์˜ ์ž๋™ ๊ฐ์ง€ ๋Œ€์‹  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํƒ€์ž…์„ ๊ฐ•์ œ๋กœ ์ง€์ •ํ•œ๋‹ค. (SERVLET, REACTIVE, NONE)์ž๋™๊ฐ์ง€
setBannerMode์‹œ์ž‘์‹œ ์ถœ๋ ฅ๋˜๋Š” ๋ฐฐ๋„ˆ์˜ ํ˜•ํƒœ๋ฅผ ์„ค์ •ํ•œ๋‹ค. (CONSOLE, LOG, OFF)CONSOLE
setAdditionalProfiles์ฝ”๋“œ ๋ ˆ๋ฒจ์—์„œ ํ™œ์„ฑํ™”ํ•  ํ”„๋กœํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•œ๋‹ค.์—†์Œ
setLazyInitialization๋นˆ(Bean)๋“ค์„ ํ•„์š”ํ•œ ์‹œ์ ์— ์ƒ์„ฑํ•˜๋„๋ก ์ง€์—ฐ ์ดˆ๊ธฐํ™” ์—ฌ๋ถ€๋ฅผ ์„ค์ •ํ•œ๋‹ค.false
addListenersํŠน์ • ๊ตฌ๋™ ๋‹จ๊ณ„์—์„œ ๋™์ž‘ํ•  ์ปค์Šคํ…€ ๋ฆฌ์Šค๋„ˆ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.
run(String… args)์„ค์ •์„ ๋งˆ์นœ ํ›„ ์‹ค์ œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌ๋™ํ•˜๋Š” ํ•ต์‹ฌ ๋ฉ”์„œ๋“œ๋‹ค.
setRegisterShutdownHookJVM ์ข…๋ฃŒ์‹œ Spring ์ปจํ…์ŠคํŠธ๊ฐ€ ์•ˆ์ „ํ•˜๊ฒŒ ๋‹ซํžˆ๋„๋ก ์…ง๋‹ค์šด ํ›…์„ ์ž๋™์œผ๋กœ ๋“ฑ๋กํ•œ๋‹ค.true
setLogStartupInfo์‹œ์ž‘์‹œ ๋ฉ”์ธํด๋ž˜์Šค ์ด๋ฆ„, ํ”„๋กœํŒŒ์ผ ์ •๋ณด, ๊ตฌ๋™ ์‹œ๊ฐ„๋“ฑ์„ ๋กœ๊ทธ๋กœ ์ถœ๋ ฅํ•œ๋‹ค.true
setHeadless์„œ๋ฒ„ ํ™˜๊ฒฝ์„ ๊ณ ๋ คํ•˜์—ฌ java.awt.headless ํ”„๋กœํผํ‹ฐ๋ฅผ true๋กœ ์ž๋™ ์„ค์ •ํ•œ๋‹ค.true
addInitializers(…)ApplicationContextInitializer๋ฅผ ์ง์ ‘ ์ถ”๊ฐ€ ํ•œ๋‹ค. Customํ•˜๊ฒŒ ์ž‘์„ฑํ•œ ApplicaltionContextInitializer๋ฅผ ์†์‰ฝ๊ฒŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

WebApplicationType ์ง์ ‘ ์ง€์ •์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ

๋Œ€๋ถ€๋ถ„์€ ์ž๋™๊ฐ์ง€๋ฅผ ํ†ตํ•ด์„œ ์‚ฌ์šฉํ•˜๊ฒ ์ง€๋งŒ ๊ฒฝ์šฐ์— ๋”ฐ๋ผ์„œ ์ง์ ‘ ์ง€์ •์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค.
1. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ถฉ๋Œ ์ƒํ™ฉ: ํ”„๋กœ์ ํŠธ์— spring-boot-starter-web๊ณผ spring-boot-starter-webflux๊ฐ€ ๋™์‹œ์— ํฌํ•จ๋˜์–ด ์žˆ๋Š” ๊ฒฝ์šฐ Spring Boot๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ SERVLET ํƒ€์ž…์„ ์šฐ์„ ํ•˜์ง€๋งŒ WebFlux๋กœ ๋Œ๋ฆฌ๊ณ  ์‹ถ๋‹ค๋ฉด ์ง์ ‘ ์ง€์ •ํ•ด์•ผ ํ•œ๋‹ค.
2. ์›น ํ™˜๊ฒฝ ์ œ์™ธ(Test/Batch): ์›น ๊ด€๋ จ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ํฌํ•จ๋˜์–ด ์žˆ์ง€๋งŒ ํŠน์ • ์‹คํ–‰ ํ™˜๊ฒฝ(์˜ˆ: ๋ฐ์ดํ„ฐ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํˆด, ๋กœ์ปฌ ๋ฐฐ์น˜ ์ž‘์—…)์—์„œ๋Š” ์„œ๋ฒ„๋ฅผ ๋„์šฐ๊ณ  ์‹ถ์ง€ ์•Š์„ ๋•Œ WebApplicationType.NONE์œผ๋กœ ๊ฐ•์ œํ•  ์ˆ˜ ์žˆ๋‹ค.
3. ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ๊ตฌ์„ฑ: ํ•˜๋‚˜์˜ ํ”„๋กœ์„ธ์Šค ๋‚ด์—์„œ ์›น ์„œ๋ฒ„๋ฅผ ๋„์šฐ๋Š” ์ปจํ…์ŠคํŠธ์™€ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋น„์›น(NONE) ์ปจํ…์ŠคํŠธ๋ฅผ ๋ถ€๋ชจ-์ž์‹ ๊ด€๊ณ„๋กœ ๋ฌถ์–ด์„œ ์‹คํ–‰ํ•˜๋Š” ํŠน์ˆ˜ํ•œ ๋Œ€๊ทœ๋ชจ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ตฌ์„ฑ์‹œ ์‚ฌ์šฉํ•œ๋‹ค.

์‚ฌ์šฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

@SpringBootApplication
public class AdvancedConfigApplication {

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(AdvancedConfigApplication.class);

        // ์…ง๋‹ค์šด ํ›… ํ™œ์„ฑํ™” (๊ธฐ๋ณธ๊ฐ’์ด true์ด์ง€๋งŒ ๋ช…์‹œ์ ์œผ๋กœ ์ œ์–ด ๊ฐ€๋Šฅ)
        // ์ปจํ…์ŠคํŠธ ์ข…๋ฃŒ ์‹œ ๋ฆฌ์†Œ์Šค ์ •๋ฆฌ๋ฅผ ๋ณด์žฅํ•œ๋‹ค.
        app.setRegisterShutdownHook(true);

        // ์‹œ์ž‘ ์ •๋ณด ๋กœ๊ทธ ์ถœ๋ ฅ ๋น„ํ™œ์„ฑํ™”
        // ์‹œ์ž‘ ์‹œ๊ฐ„์ด๋‚˜ ํ”„๋กœํŒŒ์ผ ์ •๋ณด๊ฐ€ ๋กœ๊ทธ์— ๋‚จ์ง€ ์•Š๋„๋ก ํ•œ๋‹ค.
        app.setLogStartupInfo(false);

        // 3. ํ—ค๋“œ๋ฆฌ์Šค ๋ชจ๋“œ ๋น„ํ™œ์„ฑํ™”
        // ๋งŒ์•ฝ ์„œ๋ฒ„์—์„œ GUI ๊ด€๋ จ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(๊ทธ๋ž˜ํ”„ ์ƒ์„ฑ ๋“ฑ)๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๋ฉด false๋กœ ์„ค์ •ํ•œ๋‹ค.
        app.setHeadless(false);
        
        // ์›น ํ™˜๊ฒฝ์ด ํ•„์š” ์—†๋Š” ๋ฐฐ์น˜์„ฑ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ผ ๊ฒฝ์šฐ ๊ฐ•์ œ ์ง€์ •
        app.setWebApplicationType(WebApplicationType.NONE);
        
        // ๋ฐฐ๋„ˆ๋ฅผ ๋„๊ณ  ๋กœ๊ทธ๋กœ๋งŒ ํ™•์ธํ•˜๊ณ  ์‹ถ์„ ๋•Œ
        app.setBannerMode(Banner.Mode.OFF);
        
        // ํŠน์ • ํ”„๋กœํŒŒ์ผ(์˜ˆ: 'performance')์„ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์œผ๋กœ ์ถ”๊ฐ€
        app.setAdditionalProfiles("performance");
        
        // ์‹œ์ž‘ ์‹œ๊ฐ„ ๋‹จ์ถ•์„ ์œ„ํ•ด ์ง€์—ฐ ์ดˆ๊ธฐํ™”(Lazy Initialization) ํ™œ์„ฑํ™”
        app.setLazyInitialization(true);

        // ์ˆ˜๋™์œผ๋กœ ์ดˆ๊ธฐํ™” ๊ฐ์ฒด ์ถ”๊ฐ€
        // ApplicationContext๊ฐ€ refresh๋˜๊ธฐ ์ „์— ํŠน์ • ์„ค์ •์„ ์ฃผ์ž…ํ•ฉ๋‹ˆ๋‹ค.
        // app.addInitializers(new MyCustomInitializer());

        // ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ด๋ฆ„ ์„ค์ • (Spring Boot 3.x ๊ฐ€์‹œ์„ฑ ํ–ฅ์ƒ)
        // ๋กœ๊ทธ๋‚˜ ๋ฉ”ํŠธ๋ฆญ์—์„œ ์‹๋ณ„์ž๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
        // app.setMainApplicationClass(AdvancedConfigApplication.class);

        app.run(args);
    }
}
Java

์ง€๊ธˆ๊นŒ์ง€ SpringApplication ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ์˜ ๋™์ž‘๊ณผ WebApplicationType ์ž๋™๊ฐ์ง€๊ฐ€ ์–ด๋–ป๊ฒŒ ์ด๋ฃจ์–ด์ง€๋Š”์ง€ ์‚ดํŽด๋ดค๋‹ค.

  • ํด๋ž˜์ŠคํŒจ์Šค ๊ธฐ๋ฐ˜์˜ WebApplicationType ์ž๋™ ๊ฐ์ง€
  • ๋ชจ๋“  ์˜์กด์„ฑ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ META-INF/spring.factories ๋กœ๋ถ€ํ„ฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ตฌ๋™์„ ์œ„ํ•œ ์ดˆ๊ธฐํ™” ํด๋ž˜์Šค๋“ค์„ ๋กœ๋”ฉํ•œ๋‹ค.
    • BootstrapRegistryInitializer ํƒ€์ž… ํด๋ž˜์Šค ๋กœ๋”ฉ
    • ApplicationContextInitializer ํƒ€์ž… ํด๋ž˜์Šค ๋กœ๋”ฉ
    • ApplicationListener ํƒ€์ž… ํด๋ž˜์Šค ๋กœ๋”ฉ

๋‹ค์Œ ํฌ์ŠคํŒ…์—์„œ๋Š” SpringApplication ์ธ์Šคํ„ด์Šค์˜ run() ๋ฉ”์„œ๋“œ ๋™์ž‘์„ ์ •๋ฆฌํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค.


๋‹ค์Œ์— ๋ณด๋ฉด ์ข‹์€ ํฌ์ŠคํŒ…
Spring Boot โ€“ Application Bootstraping์„ ์œ„ํ•œ 13๋‹จ๊ณ„