Spring Version 7.0 Relase Notes Summary

2025. 9. 2. 16:10ยท๐Ÿ“‚ backend/spring
2025๋…„ 11์›”์— ์˜ˆ์ •๋œ Spring Framework 7.0 ๋ฆด๋ฆฌ์ฆˆ ๋…ธํŠธ์— ๊ด€ํ•œ ๊ฐ„๋‹จํ•œ ์ •๋ฆฌ ๋ฐ ๋ฒˆ์—ญ ๊ธ€.
  • https://github.com/spring-projects/spring-framework/wiki/Spring-Framework-7.0-Release-Notes

 

Upgrading From Spring Framework 6.2

1. ์ฃผ์š” ์˜์กด์„ฑ ๋ฐ ์š”๊ตฌ์‚ฌํ•ญ ๋ณ€๊ฒฝ

์ตœ์†Œ ์š”๊ตฌ์‚ฌํ•ญ ์ƒํ–ฅ

  • JDK 17์„ ๊ธฐ๋ณธ์œผ๋กœ ์œ ์ง€ํ•˜๋ฉด์„œ JDK 25 LTS ๊ถŒ์žฅ
  • Jakarta EE 11 ๊ธฐ์ค€์„  ๋„์ž…
  • Kotlin 2.2 ๋ฐ GraalVM 24 ์ง€์›

๊ตฌ์ฒด์ ์ธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฒ„์ „ ์—…๋ฐ์ดํŠธ:

  • Servlet 6.1 (Tomcat 11.0, Jetty 12.1)
  • JPA 3.2 (Hibernate ORM 7.1)
  • Bean Validation 3.1 (Hibernate Validator 9.0)
  • Netty 4.2, Kotlin 2.2, JSONassert 2.0

 

2. ์ œ๊ฑฐ ๊ธฐ๋Šฅ

๋ชจ๋“ˆ ์ œ๊ฑฐ:

  • spring-jcl ๋ชจ๋“ˆ์ด Apache Commons Logging 1.3.0์œผ๋กœ ๋Œ€์ฒด

์–ด๋…ธํ…Œ์ด์…˜ ์ง€์› ์ค‘๋‹จ:

  • javax.annotation ๋ฐ javax.inject ํŒจํ‚ค์ง€์˜ ์–ด๋…ธํ…Œ์ด์…˜ ์ง€์› ์ค‘๋‹จ
  • @javax.annotation.Resource, @javax.annotation.PostConstruct, @javax.inject.Inject ๋“ฑ์„ jakarta.annotation ๋ฐ jakarta.inject ํŒจํ‚ค์ง€๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ•„์š”

Path Mapping ์˜ต์…˜ ์ œ๊ฑฐ:

  • suffixPatternMatch/registeredSuffixPatternMatch, trailingSlashMatch, favorPathExtension/ignoreUnknownPathExtensions ๋“ฑ ์™„์ „ ์ œ๊ฑฐ

๊ธฐํƒ€ API ์ œ๊ฑฐ:

  • ListenableFuture → CompletableFuture๋กœ ๋Œ€์ฒด
  • WebJars ์ง€์›์—์„œ webjars-locator-core → webjars-locator-lite๋กœ ๋ณ€๊ฒฝ
  • OkHttp3 ์ง€์› ์ œ๊ฑฐ

 

3. ์ง€์› ์ค‘๋‹จ(Deprecated) ๊ธฐ๋Šฅ๋“ค

  • Spring MVC์˜ <mvc:*> XML ์„ค์ • ๋„ค์ž„์ŠคํŽ˜์ด์Šค๊ฐ€ Java ์„ค์ • ๋ฐฉ์‹์œผ๋กœ ๊ถŒ์žฅ
  • Kotlin ์Šคํฌ๋ฆฝํŠธ ํ…œํ”Œ๋ฆฟ ์ง€์› ์ค‘๋‹จ
  • Spring TestContext Framework์˜ JUnit 4 ์ง€์› ์ค‘๋‹จ, JUnit Jupiter์˜ SpringExtension ๊ถŒ์žฅ
  • Jackson 2.x ์ง€์› ์ค‘๋‹จ, Jackson 3.x๋กœ ์ „ํ™˜
  • Spring MVC์—์„œ PathMatcher ์‚ฌ์šฉ ์ค‘๋‹จ
  • HandlerMappingIntrospector SPI ์ค‘๋‹จ

 

 

4. ์ฃผ์š” API ๋ณ€๊ฒฝ์‚ฌํ•ญ

Null Safety:

  • JSR 305 ๊ธฐ๋ฐ˜์˜ Spring nullness ์–ด๋…ธํ…Œ์ด์…˜์ด JSpecify ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ๋ณ€๊ฒฝ

HttpHeaders API:

  • HttpHeaders ํด๋ž˜์Šค๊ฐ€ ๋” ์ด์ƒ MultiValueMap ๊ณ„์•ฝ์„ ํ™•์žฅํ•˜์ง€ ์•Š์Œ
  • ์—ฌ๋Ÿฌ ๋ฉ”์„œ๋“œ๊ฐ€ ์ œ๊ฑฐ๋˜๊ณ  HttpHeaders#asMultiValueMap ๊ฐ™์€ ๋Œ€์ฒด ๋ฉ”์„œ๋“œ๊ฐ€ @Deprecated๋กœ ํ‘œ์‹œ

GraalVM ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ํ˜•์‹ ๋ณ€๊ฒฝ:

  • ๋ฆฌ์†Œ์Šค ํžŒํŠธ ๊ตฌ๋ฌธ์ด java.util.regex.Pattern์—์„œ "glob pattern" ํ˜•์‹์œผ๋กœ ๋ณ€๊ฒฝ
  • ํƒ€์ž…์— ๋Œ€ํ•œ reflection ํžŒํŠธ ๋“ฑ๋ก์ด ๋ฉ”์„œ๋“œ, ์ƒ์„ฑ์ž, ํ•„๋“œ ๊ฒ€์‚ฌ๋ฅผ ์•”์‹œํ•˜๋„๋ก ๋ณ€๊ฒฝ

 

 

New and Noteworthy

1. ์ƒˆ๋กœ์šด ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ชจ๋ธ

BeanRegistrar ๊ณ„์•ฝ:

  • @Configuration ํด๋ž˜์Šค์˜ ๋‹จ์ผ @Bean ๋ฉ”์„œ๋“œ ๋‚ด์—์„œ ์—ฌ๋Ÿฌ ๋นˆ์„ ๋“ฑ๋ก์„ ํ•ด์„œ๋Š” ์•ˆ๋จ. (@Bean ๋ฉ”์„œ๋“œ ํ•˜๋‚˜๋‹น ํ•˜๋‚˜์˜ ๋นˆ๋งŒ ๋“ฑ๋ก)
  • @Bean ๋ฉ”์„œ๋“œ๋Š” ๋ฐ˜ํ™˜ ํƒ€์ž…์„ ์„ ์–ธํ•  ๋•Œ ๊ฐ€๋Šฅํ•œ ๊ตฌ์ฒด์ ์ธ ํƒ€์ž…์„ ๋ช…์‹œ๋ฅผ ๊ถŒ์žฅ (๋ฐ˜ํ™˜ ํƒ€์ž…์€ List๋‚˜ Map ๊ฐ™์€ ์ถ”์ƒ ํƒ€์ž…์ด ์•„๋‹ˆ๋ผ ์‹ค์ œ ๊ตฌ์ฒด ํด๋ž˜์Šค ํƒ€์ž…์„ ์“ฐ๋Š” ๊ฒŒ ์›์น™)

 

2. SpEL ํ‘œํ˜„์‹ ๊ฐœ์„ 

Optional ํƒ€์ž… ์ง€์› ๊ฐ•ํ™”:

  • java.util.Optional ํƒ€์ž…์— ๋Œ€ํ•œ null-safe ์—ฐ์‚ฐ ์ง€์› (null-safe ์—ฐ์‚ฐ์ž(?.) ๋ฅผ ์‚ฌ์šฉ)
  • Elvis ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ•œ Optional ์ž๋™ ์–ธ๋ž˜ํ•‘ ์ง€์›

 

user?.name
  • ๋™์ž‘ ๋ฐฉ์‹
    1. user๊ฐ€ null ๋˜๋Š” Optional.empty() → ๊ฒฐ๊ณผ๋Š” null
    2. ๊ฐ’์ด ์žˆ์œผ๋ฉด user.get().getName() ํ˜ธ์ถœ๊ณผ ๋™์ผ

 

name?.orElse('Unknown')
  • Optional ์ž์ฒด์˜ ๋ฉ”์„œ๋“œ(orElse, map, filter ๋“ฑ)๋Š” ๊ทธ๋Œ€๋กœ ํ˜ธ์ถœ ๊ฐ€๋Šฅ
    1. name์ด ๋น„์–ด ์žˆ์œผ๋ฉด "Unknown" ๋ฐ˜ํ™˜
    2. ๊ฐ’์ด ์žˆ์œผ๋ฉด name.get() ๋ฐ˜ํ™˜

 

names?.?[#this.length > 5]
  • ์ปฌ๋ ‰์…˜ Optional ์˜ˆ์‹œ
    • names๊ฐ€ null ๋˜๋Š” Optional.empty() → ๊ฒฐ๊ณผ๋Š” null
    • ๊ฐ’์ด ์žˆ์œผ๋ฉด ๋‚ด๋ถ€ List<String>์„ ๋Œ€์ƒ์œผ๋กœ ๊ธธ์ด๊ฐ€ 5 ์ดˆ๊ณผ์ธ ๋ฌธ์ž์—ด ํ•„ํ„ฐ๋ง ์ˆ˜ํ–‰
      (names.get().stream().filter(...).toList()์™€ ๋™์ผ)

 

3. ํ”„๋ก์‹œ ์„ค์ • ๊ฐœ์„ 

๊ธ€๋กœ๋ฒŒ ํ”„๋ก์‹œ ํƒ€์ž… ๊ธฐ๋ณธ๊ฐ’:

  • Spring Boot์™€ ๊ฐ™์€ CGLIB ๊ธ€๋กœ๋ฒŒ ํ”„๋ก์‹œ ํƒ€์ž… ๊ธฐ๋ณธ๊ฐ’์ด ๋ชจ๋“  ํ”„๋ก์‹œ ํ”„๋กœ์„ธ์„œ(@Async ๋“ฑ ํฌํ•จ)์— ์ผ๊ด€๋˜๊ฒŒ ์ ์šฉ
  • ์ปค์Šคํ…€ ๋ชฉ์ ์„ ์œ„ํ•ด AutoProxyUtils.DEFAULT_PROXY_CONFIG_BEAN_NAME ์ด๋ฆ„์œผ๋กœ ProxyConfig ํƒ€์ž…์˜ ๋นˆ ์„ ์–ธ ๊ฐ€๋Šฅ

@Proxyable ์–ด๋…ธํ…Œ์ด์…˜:

  • ๊ฐœ๋ณ„ ๋นˆ์— ๋Œ€ํ•œ ํ”„๋ก์‹œ ์„ค์ • ์ œ์–ด๋ฅผ ์œ„ํ•œ ์ƒˆ๋กœ์šด @Proxyable ์–ด๋…ธํ…Œ์ด์…˜
  • @Proxyable(INTERFACES) ๋˜๋Š” @Proxyable(TARGET_CLASS)๋กœ ํ”„๋ก์‹œ ํƒ€์ž… ์ง€์ • ๊ฐ€๋Šฅ
  • @Proxyable(interfaces=MyService.class)๋ฅผ ํ†ตํ•œ ๋นˆ๋ณ„ ํ”„๋ก์‹œ ์ธํ„ฐํŽ˜์ด์Šค ์ง€์ • ๊ฐ€๋Šฅ

 

4. Spring Retry ํ†ตํ•ฉ

Core ๋ชจ๋“ˆ ํ†ตํ•ฉ:

  • Spring Retry ํ”„๋กœ์ ํŠธ๊ฐ€ spring-core ๋ชจ๋“ˆ์˜ org.springframework.core.retry ํŒจํ‚ค์ง€๋กœ ํ†ตํ•ฉ
  • ๋ถˆํ•„์š”ํ•œ ๊ธฐ๋Šฅ ์ œ๊ฑฐ ๋ฐ API ์žฌ๊ฒ€ํ† ๋ฅผ ํ†ตํ•œ ๊ธฐ์ดˆ์ ์ธ ์žฌ์‹œ๋„ ์ง€์› ์ œ๊ณต

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

  • spring-context ๋ชจ๋“ˆ์— @Retryable ์–ด๋…ธํ…Œ์ด์…˜ ์ง€์›
  • Spring์˜ ๋™์‹œ์„ฑ ์Šค๋กœํ‹€ ์ง€์› ๊ธฐ๋ฐ˜ @ConcurrencyLimit ์–ด๋…ธํ…Œ์ด์…˜
  • @EnableResilientMethods๋ฅผ ํ†ตํ•œ ํŽธ๋ฆฌํ•œ ํ™œ์„ฑํ™”
  • @Retryable์ด ๋ฆฌ์•กํ‹ฐ๋ธŒ ๋ฉ”์„œ๋“œ์— ์ž๋™ ์ ์‘ํ•˜์—ฌ Reactor์˜ ์žฌ์‹œ๋„ ๊ธฐ๋Šฅ์œผ๋กœ ํŒŒ์ดํ”„๋ผ์ธ ์žฅ์‹

 

5. ํ…Œ์ŠคํŠธ ์ปจํ…์ŠคํŠธ ๊ด€๋ฆฌ ๊ฐœ์„ 

์ž๋™ ์ปจํ…์ŠคํŠธ ๊ด€๋ฆฌ:

  • ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์‹œ ์ƒ์„ฑ๋œ ApplicationContext๋Š” ํ…Œ์ŠคํŠธ ์ปจํ…์ŠคํŠธ ์บ์‹œ์— ์ €์žฅ๋จ.
  • Spring 7.0๋ถ€ํ„ฐ๋Š” ์บ์‹œ์— ์ €์žฅ๋œ ์ปจํ…์ŠคํŠธ๊ฐ€ ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์œผ๋ฉด ์ž๋™์œผ๋กœ pause ์ƒํƒœ๋กœ ์ „ํ™˜๋จ.
  • ๋‹ค์‹œ ํ•„์š”ํ•  ๋•Œ ์บ์‹œ์—์„œ ๊ฐ€์ ธ์˜ค๋ฉด ์ž๋™์œผ๋กœ restart ๋˜์–ด ์›๋ž˜์˜ ๋ผ์ดํ”„์‚ฌ์ดํด ์ƒํƒœ๊ฐ€ ๋ณต์›๋จ

 

 

์ปจํ…์ŠคํŠธ ์บ์‹œ ๋ชจ๋‹ˆํ„ฐ๋ง: 

logging.level.org.springframework.test.context.cache=DEBUG
  • ํ…Œ์ŠคํŠธ๊ฐ€ ๋งŽ์„ ๊ฒฝ์šฐ ์—ฌ๋Ÿฌ ApplicationContext๊ฐ€ ์บ์‹œ์— ์Œ“์—ฌ ์‹คํ–‰ ์†๋„๊ฐ€ ๋А๋ ค์งˆ ์ˆ˜ ์žˆ์Œ.
  • ์บ์‹œ ํ˜„ํ™ฉ(์ปจํ…์ŠคํŠธ ๋ช‡ ๊ฐœ ๋กœ๋“œ๋˜์—ˆ๋Š”์ง€, ์–ผ๋งˆ๋‚˜ ์บ์‹œ๋˜์–ด ์žˆ๋Š”์ง€)์„ ๋ณด๋ ค๋ฉด:๋กœ๊น… ๋ ˆ๋ฒจ์„ ์„ค์ •ํ•˜๋ฉด ์บ์‹œ ์ƒํƒœ๋ฅผ ๋กœ๊ทธ์—์„œ ํ™•์ธ ๊ฐ€๋Šฅ.

 

์ž๋™ ์ผ์‹œ ์ •์ง€ ํšจ๊ณผ: 

  • ApplicationContext ๋‚ด๋ถ€์˜ ์ž๋™ ์‹œ์ž‘(auto-startup) Bean ๋“ค๋„ ํ•จ๊ป˜ ์ •์ง€๋จ.
  • (์˜ˆ: JMS ๋ฆฌ์Šค๋„ˆ ์ปจํ…Œ์ด๋„ˆ + ์Šค์ผ€์ค„๋Ÿฌ ํƒœ์Šคํฌ + Lifecycle / SmartLifecycle ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„์ฒด
  • ํ…Œ์ŠคํŠธ ์ค‘์— ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ๋™์•ˆ์—๋Š” ๋ฐฑ๊ทธ๋ผ์šด๋“œ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ์‹คํ–‰๋˜์ง€ ์•Š์Œ.
  • ๋‹จ, SmartLifecycle#isPauseable() = false๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋Š” ์ผ์‹œ ์ •์ง€์—์„œ ์ œ์™ธ ๊ฐ€๋Šฅ.

 

6. ์ƒˆ๋กœ์šด ํด๋ผ์ด์–ธํŠธ ์ง€์›

JmsClient ๋„์ž…:

  • JdbcClient์™€ RestClient์— ์ด์–ด ์ƒˆ๋กœ์šด JmsClient ๋„์ž…
  • JMS ๋Œ€์ƒ์— ๋Œ€ํ•œ ์ผ๋ฐ˜์ ์ธ send/receive ์—ฐ์‚ฐ ์ œ๊ณต
  • Spring์˜ ๊ณตํ†ต Message ๋˜๋Š” ํŽ˜์ด๋กœ๋“œ ๊ฐ’ ์ฒ˜๋ฆฌ, spring-messaging ๋ชจ๋“ˆ๊ณผ ์ผ์น˜ํ•˜๋Š” MessagingException ๋ฐœ์ƒ
  • JmsMessagingTemplate์˜ ๋Œ€์•ˆ์œผ๋กœ Spring JmsTemplate์— ์œ„์ž„ํ•˜์—ฌ ์‹ค์ œ ์—ฐ์‚ฐ ์ˆ˜ํ–‰

JdbcClient ๊ฐœ์„ :

  • fetch size, max rows, query timeout ๋“ฑ ๋ช…๋ น๋ฌธ ์ˆ˜์ค€ ์„ค์ •์„ ํŽธ๋ฆฌํ•˜๊ฒŒ ์ œ๊ณต

 

7. API ๋ฒ„์ „ ๊ด€๋ฆฌ ์ง€์›

Spring MVC & WebFlux๊ฐ€ API ๋ฒ„์ „ ๊ด€๋ฆฌ์— ๋Œ€ํ•œ ์ผ๊ธ‰(first-class) ์ง€์›์„ ์ œ๊ณต:

  • ์„œ๋ฒ„: ์š”์ฒญ ๋ฒ„์ „์— ๋”ฐ๋ผ ์ปจํŠธ๋กค๋Ÿฌ/๋ผ์šฐํŒ… ์ œ์–ด ๊ฐ€๋Šฅ
  • ํด๋ผ์ด์–ธํŠธ: ์š”์ฒญ์— API ๋ฒ„์ „ ์ง€์ • ๊ฐ€๋Šฅ
  • ํ…Œ์ŠคํŠธ: MockMvc, WebTestClient ์—์„œ ๋ฒ„์ „ ๊ธฐ๋ฐ˜ ์š”์ฒญ ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅ

 

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.ApiVersion;

@RestController
class UserController {

    // v1 API
    @GetMapping("/users")
    @ApiVersion("1")
    public String getUsersV1() {
        return "User list v1";
    }

    // v2 API
    @GetMapping("/users")
    @ApiVersion("2")
    public String getUsersV2() {
        return "User list v2 with more details";
    }
}

 

import org.springframework.web.reactive.function.client.WebClient;

public class ApiClient {

    private final WebClient webClient = WebClient.builder()
            .baseUrl("http://localhost:8080")
            .defaultHeader("API-Version", "2") // API ๋ฒ„์ „ ์ง€์ •
            .build();

    public String getUsers() {
        return webClient.get()
                .uri("/users")
                .retrieve()
                .bodyToMono(String.class)
                .block();
    }
}

 

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@AutoConfigureMockMvc
class UserControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    void testV1Users() throws Exception {
        mockMvc.perform(get("/users").header("API-Version", "1"))
                .andExpect(status().isOk())
                .andExpect(content().string("User list v1"));
    }

    @Test
    void testV2Users() throws Exception {
        mockMvc.perform(get("/users").header("API-Version", "2"))
                .andExpect(status().isOk())
                .andExpect(content().string("User list v2 with more details"));
    }
}

 

 

8. ์ŠคํŠธ๋ฆฌ๋ฐ ๋ฐ ์ž…์ถœ๋ ฅ ๊ฐœ์„ 

  • StreamingHttpOutputMessage.Body ๋ฉ”์„œ๋“œ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ํ†ตํ•œ ์š”์ฒญ ๋ณธ๋ฌธ์— ๋Œ€ํ•œ OutputStream ์ œ๊ณต ๊ฐ€๋Šฅ
  • InputStream ๋˜๋Š” ResponseEntity<InputStream> ๋ฐ˜ํ™˜ ๊ฐ’์„ ํ†ตํ•œ ์‘๋‹ต ์†Œ๋น„ ๊ฐ€๋Šฅ
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.io.*;

@RestController
@RequestMapping("/files")
public class FileController {

    // ํŒŒ์ผ ์—…๋กœ๋“œ (์ŠคํŠธ๋ฆฌ๋ฐ ๋ฐฉ์‹์œผ๋กœ OutputStream ์ฒ˜๋ฆฌ)
    @PostMapping(value = "/upload", consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    public ResponseEntity<String> uploadFile(InputStream inputStream) throws IOException {
        File targetFile = new File("uploaded.dat");

        try (OutputStream outputStream = new FileOutputStream(targetFile)) {
            inputStream.transferTo(outputStream); // InputStream → File
        }

        return ResponseEntity.ok("File uploaded successfully!");
    }

    // ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ (ResponseEntity<InputStream> ํ™œ์šฉ)
    @GetMapping(value = "/download", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    public ResponseEntity<InputStream> downloadFile() throws FileNotFoundException {
        File file = new File("uploaded.dat");
        InputStream inputStream = new FileInputStream(file);

        return ResponseEntity.ok()
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .body(inputStream);
    }
}

 

 

9. Path Matching ๊ฐœ์„ 

PathPattern ์™„์ „ ์ „ํ™˜:

 

  • HTTP ์š”์ฒญ ๋งคํ•‘์„ ์œ„ํ•œ ๋ ˆ๊ฑฐ์‹œ AntPathMatcher ๋ณ€ํ˜• ์ง€์› ์ค‘๋‹จ (spring reference - URI patterns)
  • ๊ฒฝ๋กœ ์‹œ์ž‘ ๋ถ€๋ถ„์—์„œ ๋งŽ์€ ๊ฒฝ๋กœ ์„ธ๊ทธ๋จผํŠธ ๋งค์นญ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ (์˜ˆ: "/**/pages/index.html")

 

๐Ÿ“Œ PathPattern vs AntPathMatcher

GPT ์—๊ฒŒ ๋ฌผ์–ด๋ณธ PathPattern vs AntPathMatcher

 

10 .HTTP ๋ฉ”์‹œ์ง€ ์ปจ๋ฒ„ํ„ฐ ๊ฐœ์„ 

1. ๊ธฐ์กด ๋ฐฉ์‹

  • Spring MVC์—์„œ HTTP ์š”์ฒญ/์‘๋‹ต ๋ณ€ํ™˜์€ HttpMessageConverter ๋“ค์ด ๋‹ด๋‹น.
  • ํ•˜์ง€๋งŒ ์„ค์ •์ด ํฉ์–ด์ ธ ์žˆ๊ฑฐ๋‚˜, ๊ฐœ๋ณ„ Bean ๋“ฑ๋ก ๋ฐฉ์‹์ด ํ•„์š”ํ•ด์„œ ์ „์—ญ์ ์œผ๋กœ ์ผ๊ด€๋˜๊ฒŒ ๊ด€๋ฆฌํ•˜๊ธฐ ์–ด๋ ค์›€.
  • WebFlux(Reactor ๊ธฐ๋ฐ˜)์—๋Š” CodecConfigurer ๊ฐ™์€ ์ค‘์•™ํ™”๋œ ์„ค์ • API๊ฐ€ ์žˆ์—ˆ์ง€๋งŒ, Spring MVC/RestTemplate ์ชฝ์€ ์ƒ๋Œ€์ ์œผ๋กœ ๋ถˆํŽธํ–ˆ์Œ.

2. ์ƒˆ๋กœ์šด HttpMessageConverters ํด๋ž˜์Šค ๋„์ž…

  • Spring 7.0์—์„œ HttpMessageConverters ๋ผ๋Š” ์ค‘์•™ ์ง‘์ค‘์‹ ๊ด€๋ฆฌ ํด๋ž˜์Šค ๋„์ž….
  • ํŠน์ง•:
    • ํด๋ž˜์ŠคํŒจ์Šค ์ž๋™ ๊ฐ์ง€ (์˜ˆ: Jackson, Gson, JAXB ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ)
    • ์ „์—ญ(Global) ๊ตฌ์„ฑ ๊ฐ€๋Šฅ
    • ์ผ๊ด€๋œ API ์ œ๊ณต → MVC, RestTemplate, RestClient ๋ชจ๋‘ ์ง€์›

3. ์žฅ์ 

  • ์ค‘์•™ํ™”๋œ ๋ฉ”์‹œ์ง€ ๋ณ€ํ™˜๊ธฐ ์„ค์ • API ์ œ๊ณต
  • Jackson, Gson ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ž๋™ ๊ฐ์ง€
  • ์„œ๋ฒ„(MVC)์™€ ํด๋ผ์ด์–ธํŠธ(RestClient, RestTemplate)์—์„œ ์ผ๊ด€๋œ ๊ตฌ์„ฑ ๊ฒฝํ—˜ ์ œ๊ณต

 

@Configuration
public class WebConfiguration implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(HttpMessageConverters.ServerBuilder builder) {
        JsonMapper jsonMapper = JsonMapper.builder()
                .findAndAddModules()
                .enable(SerializationFeature.INDENT_OUTPUT) // pretty print
                .defaultDateFormat(new SimpleDateFormat("yyyy-MM-dd")) // ๋‚ ์งœ ํฌ๋งท ์ง€์ •
                .build();

        builder.jsonMessageConverter(new JacksonJsonHttpMessageConverter(jsonMapper));
    }
}

๐Ÿ‘‰ ServerBuilder ๋ฅผ ํ†ตํ•ด ์›ํ•˜๋Š” ์ปค์Šคํ…€ JSON Converter๋ฅผ ์ถ”๊ฐ€/๋Œ€์ฒด ๊ฐ€๋Šฅ.

 

 

11. ํ…Œ์ŠคํŠธ ์ง€์› ๊ฐœ์„ 

RestTestClient:

  • WebTestClient์˜ ๋น„๋ฆฌ์•กํ‹ฐ๋ธŒ ๋ณ€ํ˜•์ธ ์ƒˆ๋กœ์šด RestTestClient ์ œ๊ณต
  • ๋ผ์ด๋ธŒ ์„œ๋ฒ„, MVC @Controller ๋˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ปจํ…์ŠคํŠธ์— ๋ฐ”์ธ๋”ฉ ๊ฐ€๋Šฅ
  • WebTestClient์™€ ๊ฐ™์€ fluent API ๋ฐ ์–ด์„ค์…˜ ๊ธฐ๋Šฅ ์ œ๊ณต

 

 

 

 

'๐Ÿ“‚ backend > spring' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

์•Œ๋ฆผ ๊ธฐ๋Šฅ Polling ์—์„œ SSE ์ „ํ™˜ํ•˜๋ฉฐ ๊ฒช์—ˆ๋˜ ์‚ฝ์งˆ (์‚ฌ์ด๋“œ ํ”„๋กœ์ ํŠธ)  (0) 2025.07.11
Presigned URL ๋กœ ํŒŒ์ผ ์—…๋กœ๋“œ ๊ธฐ๋Šฅ์„ ์™œ ์ ์šฉํ–ˆ๋ƒ๋ฉด์š”.  (1) 2025.06.01
Spring6.1 ๋ถ€ํ„ฐ ๋ณ€๊ฒฝ๋œ Parameter Name Retention  (0) 2025.03.11
์ปค์Šคํ…€ ์–ด๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜ AOP ๋ฅผ @Transactional ๋ณด๋‹ค ๋‚˜์ค‘์— ์‹คํ–‰์‹œํ‚ค๊ธฐ  (0) 2025.01.27
์ค‘๋ณต๋˜๋Š” ์Šค์ผ€์ค„๋ง ๋ถ„์‚ฐ๋ฝ์œผ๋กœ ํ•˜๋‚˜๋งŒ ์‹คํ–‰ํ•˜๊ธฐ(w.ShedLock)  (0) 2025.01.16
'๐Ÿ“‚ backend/spring' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • ์•Œ๋ฆผ ๊ธฐ๋Šฅ Polling ์—์„œ SSE ์ „ํ™˜ํ•˜๋ฉฐ ๊ฒช์—ˆ๋˜ ์‚ฝ์งˆ (์‚ฌ์ด๋“œ ํ”„๋กœ์ ํŠธ)
  • Presigned URL ๋กœ ํŒŒ์ผ ์—…๋กœ๋“œ ๊ธฐ๋Šฅ์„ ์™œ ์ ์šฉํ–ˆ๋ƒ๋ฉด์š”.
  • Spring6.1 ๋ถ€ํ„ฐ ๋ณ€๊ฒฝ๋œ Parameter Name Retention
  • ์ปค์Šคํ…€ ์–ด๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜ AOP ๋ฅผ @Transactional ๋ณด๋‹ค ๋‚˜์ค‘์— ์‹คํ–‰์‹œํ‚ค๊ธฐ
cooper25
cooper25
  • cooper25
    dev cooper
    cooper25
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
    • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (84)
      • ๐Ÿ“‚ backend (34)
        • spring (19)
        • architecture (10)
        • test (5)
      • ๐Ÿ“‚ computer-science (5)
      • ๐Ÿ“‚ programming-language (12)
        • java (12)
      • ๐Ÿ“‚ infra (9)
        • mysql (4)
        • redis (2)
        • message-queue (3)
      • ๐Ÿ“‚ cloud (2)
        • aws (2)
      • ๐Ÿ“‚ frontend (1)
        • react (0)
      • ๐Ÿ“‚ education & lecture (16)
        • ์ธํ”„๋ผ ๊ณต๋ฐฉ (11)
        • ํ•ญํ”Œ ๋ฐฑ์—”๋“œ 7๊ธฐ (5)
      • ๐Ÿ“‚ ai (1)
        • claude (1)
      • ๐Ÿ“‚ etc (2)
        • ํšŒ๊ณ  (1)
        • ์ปจํผ๋Ÿฐ์Šค (1)
  • ๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

    • ํ™ˆ
    • ํƒœ๊ทธ
    • ๋ฐฉ๋ช…๋ก
  • ๋งํฌ

  • ๊ณต์ง€์‚ฌํ•ญ

  • ์ธ๊ธฐ ๊ธ€

  • ํƒœ๊ทธ

    spring camp 2025
    UUID
    AWS
    ํ•ญํ•ดํ”Œ๋Ÿฌ์Šค
    ์ธํ”„๋ผ๊ณต๋ฐฉ
    gof
    ๋ฐ์ดํ„ฐ ์ค‘์‹ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ค๊ณ„
    react
    ๋™์‹œ์„ฑ
    Redisson
    spring AOP
    ๊ฐ€์ƒ ๋ฉด์ ‘ ์‚ฌ๋ก€๋กœ ๋ฐฐ์šฐ๋Š” ๋Œ€๊ทœ๋ชจ ์„ค๊ณ„
    ์Šคํ”„๋ง์บ ํ”„ ํ›„๊ธฐ
    kafka
    spring-batch
    spring
    JPA
    nGrinder
    ํšŒ๊ณ 
    mysql
  • ์ตœ๊ทผ ๋Œ“๊ธ€

  • ์ตœ๊ทผ ๊ธ€

  • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.6
cooper25
Spring Version 7.0 Relase Notes Summary
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”