Spring Boot

์Šคํ”„๋ง ๋ถ€ํŠธ๋Š” ํ•„์š”ํ•œ ํ™˜๊ฒฝ ์„ค์ •์„ ์ตœ์†Œํ™”ํ•˜๊ณ  ๊ฐœ๋ฐœ์ž๊ฐ€ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค˜ ์ƒ์‚ฐ์ƒ์„ ํ–ฅ์ƒ์‹œ์ผฐ๋‹ค.

ํŠน์ง•

  • ์ž„๋ฒ ๋””๋“œ ํ†ฐ์บฃ, ์ œํ‹ฐ, ์–ธ๋”ํ† ์šฐ๋ฅผ ์‚ฌ์šฉํ•ด ๋…๋ฆฝ ์‹คํ–‰์ด ๊ฐ€๋Šฅํ•œ ์Šคํ”„๋ง ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ

  • ํ†ตํ•ฉ ์Šคํƒ€ํ„ฐ๋ฅผ ์ œ๊ณตํ•˜์—ฌ maven/gradle ๊ตฌ์„ฑ ๊ฐ„์†Œํ™”

  • ์Šคํƒ€ํ„ฐ๋ฅผ ํ†ตํ•œ ์ž๋™ํ™”๋œ ์Šคํ”„๋ง ์„ค์ • ์ œ๊ณต

  • ๋ฒˆ๊ฑฐ๋กœ์šด XML ์„ค์ • ์š”๊ตฌํ•˜์ง€ ์•Š์Œ

  • JAR์„ ์‚ฌ์šฉํ•ด ์ž๋ฐ” ์˜ต์…˜๋งŒ์œผ๋กœ๋„ ๋ฐฐํฌ ๊ฐ€๋Šฅ

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ชจ๋‹ˆํ„ฐ๋ง๊ณผ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ Spring Actuator ์ œ๊ณต

  • Spring Boot Reference Guide๋ฅผ ์ฐธ๊ณ ํ•ด ์Šคํƒ€ํ„ฐ ๋‚ด๋ถ€์˜ ์˜์กด์„ฑ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

  • spring-boot-starter-web

    • spring-boot-starter-tomcat: ํ†ฐ์บฃ(์›น์„œ๋ฒ„)

    • spring-webmvc: ์Šคํ”„๋ง ์›น MVC

  • spring-boot-starter-thymeleaf: ํƒ€์ž„๋ฆฌํ”„ ํ…œํ”Œ๋ฆฟ ์—”์ง„(View)

  • spring-boot-starter: ์Šคํ”„๋ง ๋ถ€ํŠธ + ์Šคํ”„๋ง ์ฝ”์–ด + ๋กœ๊น…

    • spring-boot

      • spring-core

    • spring-boot-starter-logging

      • logback, slf4j

  • spring-boot-starter-test: ์Šคํ”„๋ง๋ถ€ํŠธ ํ…Œ์ŠคํŠธ

์žฅ๋‹จ์ 

์žฅ์ 

  • ๊ฐ๊ฐ์˜ ์˜์กด์„ฑ ๋ฒ„์ „์„ ์˜ฌ๋ฆฌ๋Š” ๊ฒƒ์ด ์กฐ๊ธˆ ๋” ์ˆ˜์›”ํ•˜๋‹ค.

  • ํŠน์ • ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋ฒ„๊ทธ๊ฐ€ ์žˆ๋”๋ผ๋„ ์Šคํ”„๋งํŒ€์˜ ๋ฒ„๊ทธ ํ”ฝ์Šคํ•œ ๋ฒ„์ „์„ ๋ฐ›๊ธฐ ํŽธ๋ฆฌํ•˜๋‹ค.

  • ๊ฐ„๋‹จํ•œ ์–ด๋…ธํ…Œ์ด์…˜ ์„ค์ •์ด๋‚˜ ํ”„๋กœํผํ‹ฐ ์„ค์ •์œผ๋กœ ์„ธ๋ถ€์ ์ธ ์„ค์ • ์—†์ด ์›ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๋น ๋ฅด๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ๋ณ„๋„์˜ ์™ธ์žฅ ํ†ฐ์บฃ์„ ์„ค์น˜ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

๋‹จ์ 

  • ์„ค์ •์„ ๊ฐœ์ธํ™”ํ•˜๋ฉด ๋ฒ„์ „์„ ์˜ฌ๋ฆด ๋•Œ ๊ธฐ์กด ์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•œ ๋ถˆํŽธํ•จ์„ ๊ฒช์„ ์ˆ˜ ์žˆ๋‹ค.

  • ํŠน์ • ์„ค์ •์„ ๊ฐœ์ธํ™” ํ˜น์€ ์„ค์ • ์ž์ฒด๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, ๋‚ด๋ถ€์˜ ์„ค์ • ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ด์•ผํ•˜๋Š” ๋ถˆํŽธํ•จ์ด ์žˆ๋‹ค.

์ž๋™ ํ™˜๊ฒฝ ์„ค์ •

์Šคํ”„๋ง ๋ถ€ํŠธ ์ž๋™ ํ™˜๊ฒฝ์„ค์ •์€ Web, H2, JDBC๋ฅผ ๋น„๋กฏํ•ด ์•ฝ 100์—ฌ ๊ฐœ์˜ ์ž๋™ ์„ค์ •์„ ์ œ๊ณตํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ƒˆ๋กœ ์ถ”๊ฐ€๋˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์Šคํ”„๋ง ๋ถ€ํŠธ ์ž๋™-์„ค์ • ์˜์กด์„ฑ์— ๋”ฐ๋ผ ์„ค์ •์ด ์ž๋™ ์ ์šฉ๋œ๋‹ค. ์ž๋™ ์„ค์ •์€ @EnableAutoConfiguration (@Configuration๊ณผ ๋ฐ˜๋“œ์‹œ ๊ฐ™์ด ์‚ฌ์šฉ) ๋˜๋Š” @SpringBootApplication ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ๋Š” ์˜์กด์„ฑ์„ ์ผ์ผ์ด ๋นˆ์œผ๋กœ ์„ค์ •ํ–ˆ์œผ๋‚˜, ์Šคํ”„๋ง ๋ถ€ํŠธ๋Š” ๊ด€๋ จ ์˜์กด์„ฑ์„ ์Šคํƒ€ํ„ฐ๋ผ๋Š” ๋ฌถ์Œ์œผ๋กœ ์ œ๊ณตํ•ด ์ˆ˜๋™ ์„ค์ •์„ ์ง€์–‘ํ•œ๋‹ค.

@SpringBootApplication

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
  ...
}
  • @SpringBootConfiguration : ์Šคํ”„๋ง ๋ถ€ํŠธ์˜ ์„ค์ •์„ ๋‚˜ํƒ€๋‚ด๋Š” ์–ด๋…ธํ…Œ์ด์…˜

    • Spring์˜ @Configuration ๋Œ€์ฒด

    • ์Šคํ”„๋ง๋ถ€ํŠธ ์ „์šฉ

  • @EnableAutoConfiguration : ์ž๋™ ์„ค์ •์˜ ํ•ต์‹ฌ ์–ด๋…ธํ…Œ์ด์…˜

    • ํด๋ž˜์Šค ๊ฒฝ๋กœ์— ์ง€์ •๋œ ๋‚ด์šฉ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ž๋™ ์„ค์ •

    • ํŠน๋ณ„ํ•œ ์„ค์ •๊ฐ’์„ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์œผ๋ฉด default๊ฐ’ ์„ค์ •

  • @ComponentScan : ํŠน์ • ํŒจํ‚ค์ง€ ๊ฒฝ๋กœ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ @configuration์—์„œ ์‚ฌ์šฉํ•  @Component ์„ค์ • ํด๋ž˜์Šค๋ฅผ ์ฐพ๋Š”๋‹ค.

    • basePackages ํ”„๋กœํผํ‹ฐ ๊ฐ’์— ๋ณ„๋„๋กœ ๊ฐ’์„ ์„ค์ •ํ•˜์ง€ ์•Š์œผ๋ฉด, @ComponentScan์ด ์œ„์น˜ํ•œ ํŒจํ‚ค์ง€๊ฐ€ ๋ฃจํŠธ ๊ฒฝ๋กœ๋กœ ์„ค์ •

@EnableAutoConfiguration

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

์—ฌ๊ธฐ์„œ ์ž๋™ ์„ค์ •์„ ์ง€์›ํ•ด์ฃผ๋Š” ์–ด๋…ธํ…Œ์ด์…˜์€ @Import({AutoConfigurationImportSelector.class})์ด๋‹ค.

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
    private static final AutoConfigurationImportSelector.AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationImportSelector.AutoConfigurationEntry();
    private static final String[] NO_IMPORTS = new String[0];
    private static final Log logger = LogFactory.getLog(AutoConfigurationImportSelector.class);
    private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";
    private ConfigurableListableBeanFactory beanFactory;
    private Environment environment;
    private ClassLoader beanClassLoader;
    private ResourceLoader resourceLoader;
    private AutoConfigurationImportSelector.ConfigurationClassFilter configurationClassFilter;

    public AutoConfigurationImportSelector() {
    }

    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }
  ...
}

AutoConfigurationImportSelector ๋‚ด๋ถ€์˜ selectImports()์—๋Š” ์ž๋™ ์„ค์ • ๋ฐฉ์‹์— ๋Œ€ํ•ด ์กฐ๊ธˆ ๋” ์ƒ์„ธํžˆ ์‚ดํŽด๋ณผ ์ˆ˜ ์žˆ๋‹ค.

    protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            configurations = this.removeDuplicates(configurations);
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.getConfigurationClassFilter().filter(configurations);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

getAutoConfigurationEntry() ๋ฉ”์„œ๋“œ๋ฅผ ๋ณด๋ฉด removeDuplicates() ์ข…๋ณต๋œ ์„ค์ •๊ณผ getExclusions()์œผ๋กœ ์ œ์™ธํ•  ์„ค์ •์„ ์ œ์™ธ์‹œ์ผœ์ฃผ๊ณ  ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‚˜์„œ ์ด์ค‘์— ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋นˆ๋งŒ ์ž„ํฌํŠธํ•  ์ž๋™ ๋Œ€์ƒ์œผ๋กœ ์„ ํƒํ•˜๊ณ  ์žˆ๋‹ค.

  • META-INF/spring.factories : ์ž๋™ ์„ค์ • ํƒ€๊นƒ ํด๋ž˜์Šค ๋ชฉ๋ก. ์ด๊ณณ์— ์„ ์–ธ๋˜์–ด ์žˆ๋Š” ํด๋ž˜์Šค๋“ค์ด @EnableAutoConfiguration ์˜ ํƒ€๊ฒŸ

  • META-INF/spring-configuration-metadata.json : ์ž๋™ ์„ค์ •์— ์‚ฌ์šฉํ•  ํ”„๋กœํผํ‹ฐ ์ •์˜ ํŒŒ์ผ.

    • ๋ฏธ๋ฆฌ ๊ตฌํ˜„๋˜์–ด ์žˆ๋Š” ์ž๋™ ์„ค์ •์— ํ”„๋กœํผํ‹ฐ๋งŒ ์ฃผ์ž… ์‹œํ‚ค๋ฉด ๋œ๋‹ค.(๋ณ„๋„ ํ™˜๊ฒฝ์„ค์ • ๋ถˆํ•„์š”)

  • org/springframework/boot/autoconfigure : ๋ฏธ๋ฆฌ ๊ตฌํ˜„ํ•ด๋†“์€ ์ž๋™ ์„ค์ • ๋ฆฌ์ŠคํŠธ

    • {ํŠน์ •์„ค์ •์ด๋ฆ„}AutoConfiguration ํ˜•์‹์œผ๋กœ ์ด๋ฆ„์ด ์ง€์ •๋˜์–ด ์žˆ์Œ

์œ„ ํŒŒ์ผ์€ ๋ชจ๋‘ spring-boot-autoconfiguration์— ๋ฏธ๋ฆฌ ์ •์˜๋˜์–ด ์žˆ๊ณ , ์ง€์ •๋œ ํ”„๋กœํผํ‹ฐ ๊ฐ’์„ ์‚ฌ์šฉํ•ด ์„ค์ • ํด๋ž˜์Šค ๋‚ด๋ถ€ ๊ฐ’์„ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋‹ค.

Spring Boot Reference Guide - Common Application properties์—์„œ ํ”„๋กœํผํ‹ฐ ๊ฐ’์„ ์‰ฝ๊ฒŒ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ž๋™ ์„ค์ • ์–ด๋…ธํ…Œ์ด์…˜

์ž๋™ ์„ค์ • ์กฐ๊ฑด ์–ด๋…ธํ…Œ์ด์…˜

์–ด๋…ธํ…Œ์ด์…˜

์ ์šฉ ์กฐ๊ฑด

@ConditionalOnBean

ํ•ด๋‹นํ•˜๋Š” ๋นˆ ํด๋ž˜์Šค๋‚˜ ์ด๋ฆ„์ด ๋ฏธ๋ฆฌ ๋นˆ ํŒฉํ† ๋ฆฌ์— ํฌํ•จ๋˜์–ด ์žˆ๋Š” ๊ฒฝ์šฐ

@ConditionalOnClass

ํ•ด๋‹นํ•˜๋Š” ํด๋ž˜์Šค๊ฐ€ ํด๋ž˜์Šค ๊ฒฝ๋กœ์— ์žˆ๋Š” ๊ฒฝ์šฐ

@ConditionalOnCloudPlatform

ํ•ด๋‹นํ•˜๋Š” ํด๋ผ์šฐ๋“œ ํ”Œ๋žซํผ์ด ํ™œ์šฉ ์ƒํƒœ์ธ ๊ฒฝ์šฐ

@ConditionalOnExpression

SpEL์— ์˜์กดํ•˜๋Š” ์กฐ๊ฑด์ธ ๊ฒฝ์šฐ

@ConditionalOnJava

JVM ๋ฒ„์ „์ด ์ผ์น˜ํ•˜๋Š” ๊ฒฝ์šฐ

@ConditionalOnJndi

JNDI๊ฐ€ ์‚ฌ์šฉ๊ฐ€๋Šฅํ•˜๊ณ  ํŠน์ • ์œ„์น˜์— ์žˆ๋Š” ๊ฒฝ์šฐ

@ConditionalOnMissingBean

ํ•ด๋‹นํ•˜๋Š” ๋นˆ ํด๋ž˜์Šค๋‚˜ ์ด๋ฆ„์ด ๋ฏธ๋ฆฌ ๋นˆ ํŒฉํ† ๋ฆฌ์— ํฌํ•จ๋˜์–ด ์žˆ์ง€ ์•Š์€ ๊ฒฝ์šฐ

@ConditionalOnMissingClass

ํ•ด๋‹นํ•˜๋Š” ํด๋ž˜์Šค๊ฐ€ ํด๋ž˜์Šค ๊ฒฝ๋กœ์— ์—†์„ ๊ฒฝ์šฐ

@ConditionalOnNotWebApplication

์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์•„๋‹Œ๊ฒฝ์šฐ

@ConditionalOnProperty

ํŠน์ •ํ•œ ํ”ผ๋กœํผํ‹ฐ๊ฐ€ ์ง€์ •ํ•œ ๊ฐ’์„ ๊ฐ–๋Š” ๊ฒฝ์šฐ

@ConditionalOnResource

ํŠน์ • ๋ฆฌ์†Œ์Šค๊ฐ€ ํด๋ž˜์Šค ๊ฒฝ๋กœ์— ์žˆ๋Š” ๊ฒฝ์šฐ

@ConditionalOnSingleCandidate

์ง€์ •ํ•œ ๋นˆ ํด๋ž˜์Šค๊ฐ€ ์ด๋ฏธ ๋นˆ ํŒฉํ† ๋ฆฌ์— ํฌํ•จ๋˜์–ด ์žˆ๊ณ  ๋‹จ์ผ ํ›„๋ณด์ž๋กœ ์ง€์ • ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ

@ConditionalOnWebApplication

์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ธ ๊ฒฝ์šฐ

์ž๋™ ์„ค์ • ์ˆœ์„œ ์–ด๋…ธํ…Œ์ด์…˜

์–ด๋…ธํ…Œ์ด์…˜

์„ค๋ช…

@AutoConfigureAfter

์ง€์ •ํ•œ ํŠน์ • ์ž๋™ ์„ค์ • ํด๋ž˜์Šค๋“ค์ด ์ ์šฉ๋œ ์ดํ›„์— ํ•ด๋‹น ์ž๋™ ์„ค์ • ์ ์šฉ

@AutoConfigureBefore

์ง€์ •ํ•œ ํŠน์ • ์ž๋™ ์„ค์ • ํด๋ž˜์Šค๋“ค์ด ์ ์šฉ๋œ ์ด์ „์— ํ•ด๋‹น ์ž๋™ ์„ค์ • ์ ์šฉ

@AutoConfigureOrder

์ž๋™ ์„ค์ • ์ˆœ์„œ ์ง€์ •์„ ์œ„ํ•œ ์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ์˜ @Order ์–ด๋…ธํ…Œ์ด์…˜ ๋ณ€ํ˜•์œผ๋กœ ๊ธฐ์กด ์„ค์ • ํด๋ž˜์Šค์—๋Š” ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๊ณ  ์ž๋™ ์„ค์ • ํด๋ž˜์Šค๋“ค ๊ฐ„์˜ ์ˆœ์„œ๋งŒ ์ง€์ •ํ•œ๋‹ค.

์˜ˆ์‹œ

@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) // ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ผ ๋–„
@ConditionalOnClass(WebServlet.class) // WebServlet.class๊ฐ€ ๊ฒฝ๋กœ์— ์žˆ์„๋•Œ
@ConditionalOnProperty(prefix = "spring.h2.console" , name = "enabled", havingValue = "true", matchIfMissing = false) // spring.h2.console.enabled ๊ฐ’์ด true์ผ๋•Œ
@EnableConfigurationProperties(H2ConsoleProperties.class)
public class H2ConsoleAutoConfiguration {
  ...
}

Last updated