2 ๋ถ„ ์†Œ์š”

์Šคํ”„๋ง ๋ถ€ํŠธ์˜ ์ž๋™ ๊ตฌ์„ฑ๊ณผ ํ…Œ์ŠคํŠธ๋กœ ์ „ํ™˜

์ง์ ‘ ๊ตฌํ˜„ํ–ˆ๋˜ ์ž๋™ ๊ตฌ์„ฑ ํด๋ž˜์Šค์™€ ์• ๋…ธํ…Œ์ด์…˜ ๋“ฑ์„ ์ œ๊ฑฐํ•œ๋‹ค.
๋ฉ”์ธ ์• ๋…ธํ…Œ์ด์…˜์„ ์Šคํ”„๋ง ๋ถ€ํŠธ์˜ @SpringBootApplication๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.

@SpringBootApplication
public class HellobootApplication {

ํ…Œ์ŠคํŠธ์šฉ์œผ๋กœ ์Šคํ”„๋ง ๋ถ€ํŠธ๊ฐ€ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๋‚ด์žฅํ˜• DB๋ฅผ ์ด์šฉํ•ด์„œ ๋ฐ์ดํ„ฐ ์•ก์„ธ์Šค ๋กœ์ง๋งŒ ํ…Œ์ŠคํŠธ ํ•  ๋•Œ๋Š” @JdbcTest๋ฅผ ์‚ฌ์šฉ ํ•  ์ˆ˜ ์žˆ๋‹ค. ํ”„๋กœํผํ‹ฐ๋กœ ์„ค์ •ํ•œ DB ์ ‘์† ์ •๋ณด๊ฐ€ ์‚ฌ์šฉ๋˜์ง€ ์•Š์œผ๋‹ˆ ์ฃผ์˜ํ•  ๊ฒƒ.

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋„์šฐ๊ณ  ์ž๋™ ๊ตฌ์„ฑ๊นŒ์ง€ ์ ์šฉํ•ด์„œ ํ…Œ์ŠคํŠธ๋ฅผ ํ•  ๋•Œ๋Š” ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋„์šธ ๊ฒƒ์ธ๊ฐ€์— ๋”ฐ๋ผ์„œ ๋‹ค์Œ ๋‘ ๊ฐ€์ง€ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
๋กค๋ฐฑ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด์„œ๋Š” @Transactional์„ ๋„ฃ์–ด์ค˜์•ผ ํ•œ๋‹ค.

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
@Transactional
public class HelloRepositoryTest {

์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋„์›Œ์„œ HTTP ์š”์ฒญ์„ ๋ณด๋‚ด์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•  ๋•Œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ…Œ์ŠคํŠธ๋ฅผ ์ค€๋น„ํ•œ๋‹ค.

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class HelloApiTest {

ํ”„๋กœํผํ‹ฐ์˜ ์ด๋ฆ„์€ ์Šคํ”„๋ง ๋ถ€ํŠธ์˜ ์ž๋™ ๊ตฌ์„ฑ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณ€๊ฒฝํ•ด์ค˜์•ผ ํ•œ๋‹ค.

์Šคํ”„๋ง ๋ถ€ํŠธ ์ž์„ธํžˆ ์‚ดํŽด๋ณด๊ธฐ

image

์Šคํ”„๋ง ๋ถ€ํŠธ์˜ ๋™์ž‘ ๋ฐฉ์‹์„ ์ดํ•ดํ•˜๊ณ , ์ž์‹ ์ด ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ์ˆ ๊ณผ ๊ด€๋ จ๋œ ์ž๋™ ๊ตฌ์„ฑ๊ณผ ํ”„๋กœํผํ‹ฐ ๋“ฑ์„ ๋ถ„์„ํ•˜๊ณ , ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํŒŒ์•…ํ•˜๋Š” ๊ฒƒ์ด ํ•„์š”ํ•˜๋‹ค.

image

์Šคํ”„๋ง ๋ถ€ํŠธ์˜ ์ž๋™ ๊ตฌ์„ฑ์œผ๋กœ๋ถ€ํ„ฐ ํ•™์Šตํ•  ๊ธฐ์ˆ ์„ ํ•˜๋‚˜์”ฉ ์ฐพ์•„์„œ ํ•„์š”ํ•œ ๋ถ€๋ถ„์„ ๊ณต๋ถ€ํ•˜๋Š” ์ ‘๊ทผ ๋ฐฉ๋ฒ•๋„ ์œ ์šฉํ•˜๋‹ค.

์ž๋™ ๊ตฌ์„ฑ ๋ถ„์„ ๋ฐฉ๋ฒ•

image

  • ์ž๋™ ๊ตฌ์„ฑ ํ›„๋ณด ๋ชฉ๋ก๊ณผ ์กฐ๊ฑด ํŒ๋‹จ ๊ฒฐ๊ณผ๋ฅผ ์กฐํšŒํ•˜๋ ค๋ฉด -Ddebug์ด๋‚˜ โ€“debug ์ธ์ž ๊ฐ’์„ ์ด์šฉํ•ด์„œ ์Šคํ”„๋ง ๋ถ€ํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹œ์ž‘ํ•˜๋ฉด ๋œ๋‹ค.
  • ์ฝ”๋“œ๋ฅผ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์ œ๊ณต๋œ๋‹ค. ConditionEvaluationReport ํƒ€์ž…์˜ ๋นˆ์„ ์ฃผ์ž… ๋ฐ›์•„์„œ ํ•„์š”ํ•œ ์ •๋ณด๋งŒ ์„ ํƒํ•ด์„œ ์ž๋™ ๊ตฌ์„ฑ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.
  • ์ตœ์ข…์ ์œผ๋กœ ๋“ฑ๋ก๋œ ๋นˆ ๋ชฉ๋ก์„ ๋ณด๊ณ  ์‹ถ์œผ๋ฉด ListableBeanFactory ํƒ€์ž…์˜ ๋นˆ์„ ์ฃผ์ž… ๋ฐ›์•„์„œ ๋นˆ ์ด๋ฆ„์„ ๋ชจ๋‘ ๊ฐ€์ ธ์˜ค๊ณ , ํ•„์š”ํ•˜๋ฉด ๋นˆ ์˜ค๋ธŒ์ ํŠธ๋„ ๊ฐ€์ ธ์™€์„œ ์‚ดํŽด๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์ž๋™ ๊ตฌ์„ฑ ์„ ์ • ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์Šคํ”„๋ง ๋ถ€ํŠธ ๋ ˆํผ๋Ÿฐ์Šค ๋ฌธ์„œ, ๊ทธ๋ฆฌ๊ณ  ์ž๋™ ๊ตฌ์„ฑ ํด๋ž˜์Šค์˜ ์†Œ์Šค ์ฝ”๋“œ, ํ”„๋กœํผํ‹ฐ ํด๋ž˜์Šค, ์ปค์Šคํ† ๋งˆ์ด์ € ๋“ฑ์„ ์ฐจ๊ทผ์ฐจ๊ทผ ๋”ฐ๋ผ์„œ ์‚ดํŽด๋ณด๋ฉด์„œ ์–ด๋–ป๊ฒŒ ์–ด๋–ค ์กฐ๊ฑด์œผ๋กœ ๋™์ž‘ํ• ์ง€ ๋ถ„์„ํ•œ๋‹ค.

์ž๋™ ๊ตฌ์„ฑ ์กฐ๊ฑด ๊ฒฐ๊ณผ ํ™•์ธ

ConditionEvaluationReport๋ฅผ ์ด์šฉํ•ด์„œ ์กฐ๊ฑด์ด ๋งค์นญ๋œ ์ž๋™ ๊ตฌ์„ฑ ํด๋ž˜์Šค์™€ ๋ฉ”์†Œ๋“œ๋ฅผ ์ถœ๋ ฅํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ ์ค‘์—์„œ Jmx ๊ด€๋ จ ๊ตฌ์„ฑ ์ •๋ณด๋Š” ์ œ์™ธํ•˜๊ณ  ์‹ถ์œผ๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ๋œ๋‹ค.

@Bean ApplicationRunner run(ConditionEvaluationReport report) {
    return args -> {
        System.out.println(report.getConditionAndOutcomesBySource().entrySet().stream()
            .filter(co -> co.getValue().isFullMatch())
            .filter(co -> co.getKey().indexOf("Jmx") < 0)
            .map(co -> {
                System.out.println(co.getKey());
                co.getValue().forEach(c -> {
                    System.out.println("\t" + c.getOutcome());
                });
                System.out.println();
                return co;
        }).count());
    };
}

Core ์ž๋™ ๊ตฌ์„ฑ ์‚ดํŽด๋ณด๊ธฐ

@ConditionalOnProperty ์กฐ๊ฑด์ธ ๊ฒฝ์šฐ matchIfMissing = true๋ผ๋ฉด ํ”„๋กœํผํ‹ฐ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์•„๋„ ์กฐ๊ฑด์ด ๋งค์นญ๋œ๋‹ค.

@AutoConfiguration
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

Web ์ž๋™ ๊ตฌ์„ฑ ์‚ดํŽด๋ณด๊ธฐ

์›น ์Šคํƒ€ํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ๋งŒ ํ•ด๋„ 50๊ฐœ ๊ฐ€๊นŒ์šด ์ž๋™ ๊ตฌ์„ฑ ํด๋ž˜์Šค์™€ ๋นˆ ๋ฉ”์†Œ๋“œ ์กฐ๊ฑด์ด ์ถ”๊ฐ€๋œ๋‹ค.

@ConditionalOnClass ๋“ฑ์ด ๋ถ™์€ ํด๋ž˜์Šค์— @Import๊ฐ€ ๋ถ™์–ด์žˆ๋Š” ๊ฒฝ์šฐ์—” ํด๋ž˜์Šค ๋ ˆ๋ฒจ์˜ ์กฐ๊ฑด์ด ๋ชจ๋‘ ๋งŒ์กฑํ•˜๋Š” ๊ฒฝ์šฐ @Import๊ฐ€ ๋™์ž‘ํ•ด์„œ ์ž๋™ ๊ตฌ์„ฑ์„ ์ถ”๊ฐ€์‹œ๊ธฐ๋„ ํ•œ๋‹ค.

@AutoConfiguration(
    after = { GsonAutoConfiguration.class, JacksonAutoConfiguration.class, JsonbAutoConfiguration.class })
@ConditionalOnClass(HttpMessageConverter.class)
@Conditional(NotReactiveWebApplicationCondition.class)
@Import({ JacksonHttpMessageConvertersConfiguration.class, GsonHttpMessageConvertersConfiguration.class,
    JsonbHttpMessageConvertersConfiguration.class })
public class HttpMessageConvertersAutoConfiguration {


Customizer ๋นˆ์„ ์ด์šฉํ•˜๋Š” ์ž๋™ ๊ตฌ์„ฑ์€ ํ”„๋กœํผํ‹ฐ ๋นˆ์„ Customizer๊ฐ€ ์ฃผ์ž…์„ ๋ฐ›๊ณ , ์ด๋ฅผ ๋นˆ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฉ”์†Œ๋“œ์—์„œ Customizer๋ฅผ ์ฃผ์ž… ๋ฐ›์•„์„œ ํ”„๋กœํผํ‹ฐ ์„ค์ • ๋กœ์ง์„ ์ ์šฉํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•˜๊ธฐ๋„ ํ•œ๋‹ค.


์ตœ์ข… ๋นˆ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ๋งŒ๋“œ๋Š” Builder๋ฅผ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•˜๋Š” ๊ฒฝ์šฐ๋„ ์žˆ๋‹ค. ์ด ๋นŒ๋” ๋นˆ์„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๊ฐ€์ ธ๋‹ค ์‚ฌ์šฉํ•ด์„œ ๋นˆ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ง์ ‘ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.
RestTemplateBuilder ์ฒ˜๋Ÿผ ๋นŒ๋”๋งŒ ์ž๋™ ๊ตฌ์„ฑ์œผ๋กœ ์ œ๊ณตํ•˜๋Š” ๊ฒฝ์šฐ๋„ ์žˆ๋‹ค.

@Bean
@Lazy
@ConditionalOnMissingBean
public RestTemplateBuilder restTemplateBuilder(RestTemplateBuilderConfigurer restTemplateBuilderConfigurer) {
    RestTemplateBuilder builder = new RestTemplateBuilder();
    return restTemplateBuilderConfigurer.configure(builder);
}

Jdbc ์ž๋™ ๊ตฌ์„ฑ ์‚ดํŽด๋ณด๊ธฐ

DataSource ์ž๋™ ๊ตฌ์„ฑ์—์„œ driver class name์„ ํ”„๋กœํผํ‹ฐ์— ๋„ฃ์ง€ ์•Š์œผ๋ฉด url์„ ์ด์šฉํ•ด์„œ ๋“œ๋ผ์ด๋ฒ„์™€ ํด๋ž˜์Šค ์ด๋ฆ„์„ ๋„ฃ์–ด์ค€๋‹ค. ๋‚ด์žฅํ˜• DB๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์— DataSource ํ”„๋กœํผํ‹ฐ๊ฐ€ ์—†์œผ๋ฉด ์Šคํ”„๋ง ๋ถ€ํŠธ๊ฐ€ ์ž๋™์œผ๋กœ ์—ฐ๊ฒฐ ์ •๋ณด๋ฅผ ์„ค์ •ํ•ด์ค€๋‹ค.


JdbcTransactionManager๋Š” ๊ธฐ์กด DataSourceTransactionManager์— ์˜ˆ์™ธ ์ถ”์ƒํ™” ์ž‘์—…์˜ ๋ณ€๊ฒฝ์ด ๋ฐ˜์˜๋˜์–ด์žˆ๋‹ค. ๊ธฐ์กด ๋ฒ„ ์ „๊ณผ ํ˜ธํ™˜์„ ์œ„ํ•ด์„œ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ง€์ •ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์„ ํƒ๋œ๋‹ค.


@AutoConfiguration์€ ์ž๋™ ๊ตฌ์„ฑ์„ ์ง„ํ–‰ํ•  ์ „ํ›„ ์ˆœ์„œ๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

@AutoConfiguration(after = DataSourceAutoConfiguration.class)


TransactionProperties๋Š” PlatformTransactionManagerCustomizer๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค. ํ”„๋กœํผํ‹ฐ ํด๋ž˜์Šค๊ฐ€ ์ž์‹ ์ด ๊ฐ€์ง„ ๊ฐ’์„ ์ด์šฉํ•˜๋Š” ๊ฐ„๋‹จํ•œ Customizer ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ด์„œ ์‚ฌ์šฉํ•˜๋˜๊ธฐ๋„ ํ•œ๋‹ค.

@ConfigurationProperties(prefix = "spring.transaction")
public class TransactionProperties implements PlatformTransactionManagerCustomizer<AbstractPlatformTransactionManager> {

์ •๋ฆฌ

image

image

image

์นดํ…Œ๊ณ ๋ฆฌ:

์—…๋ฐ์ดํŠธ:

๋Œ“๊ธ€๋‚จ๊ธฐ๊ธฐ