이번 포스팅에서는 Spring Boot 4.1 신기능에 대해서 정리하고자 한다. Spring Boot 4.0이 Spring Framework 7과 함께 등장하며 Java 17 베이스라인과 null-safety 기반을 다졌다면, 4.1은 그 위에서 실무자가 바로 체감할 수 있는 기능을 대거 채워 넣은 릴리스다. gRPC를 스타터 하나로 붙일 수 있게 됐고, Jackson 동작을 프로퍼티로 세밀하게 조정할 수 있으며, HTTP 클라이언트가 SSRF를 스스로 막기 시작했다. 여기에 커넥션 풀을 아끼는 Lazy JDBC 옵션과 @Async 구간까지 이어지는 트레이스 전파가 더해졌다. 릴리스 노트에 흩어져 있는 변화를 실무 관점에서 다시 묶어 코드와 함께 살펴본다.
Spring Boot 4.1, 결국 뭐가 달라졌나

Spring Boot 4.1은 4.0의 기반 위에 실무 편의 기능을 채운 마이너 릴리스다. 가장 큰 변화는 gRPC 네이티브 지원, Jackson read/write 세밀 제어, HTTP 클라이언트 SSRF 방어, Lazy JDBC 커넥션 페칭 네 가지다. 여기에 Spring Framework 7.0.8, Spring Data 2026.0.0으로 의존성이 올라가고 jOOQ 3.21이 Java 21 이상을 요구한다.
| 항목 | Spring Boot 4.0 | Spring Boot 4.1 |
|---|---|---|
| gRPC | 별도 서드파티 스타터 필요 | spring-boot-starter-grpc-server 공식 제공 |
| Jackson 제어 | 매퍼별 커스터마이저 필요 | spring.jackson.read.* / write.*로 포맷 공통 스트리밍 기능 노출 |
| HTTP 클라이언트 보안 | 수동 구성 | InetAddressFilter 기반 SSRF 방어 내장 |
| JDBC 커넥션 | 즉시(eager) 획득 | connection-fetch=lazy 지연 획득 지원 |
| Spring Framework | 7.0.x | 7.0.8 |
| jOOQ | Java 17 | Java 21 이상 필요 |
위 표는 4.0에서 4.1로 넘어올 때 체감이 큰 변화만 추린 것이다. 대부분 하위 호환을 유지하지만 jOOQ와 일부 도구는 Java 21을 요구하므로, 아직 Java 17에 머물러 있다면 업그레이드 계획을 함께 세워야 한다. 각 항목의 상세 내용은 Spring Boot 4.1 릴리스 노트에 정리돼 있다.
gRPC를 스타터 하나로 붙이는 시대
Spring Boot 4.1에서 가장 눈에 띄는 변화는 gRPC 서버·클라이언트를 공식 스타터로 지원한다는 점이다. 그동안 LogNet이나 yidongnan 같은 서드파티 스타터에 의존하던 부분이 spring-boot-starter-grpc-server로 표준화됐다. BindableService를 구현한 빈을 등록하면 Spring gRPC가 자동으로 감지해 서버에 바인딩한다.
// build.gradle
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-grpc-server'
}Groovy먼저 위와 같이 gRPC 서버 스타터를 의존성에 추가한다. 이 스타터는 Netty 기반 독립 실행 서버뿐 아니라 서블릿 컨테이너 위에서 HTTP/2로 노출하는 방식도 함께 지원한다. 별도 플러그인 설정 없이 스타터만으로 자동 구성이 활성화되는 것이 핵심이다.
import io.grpc.stub.StreamObserver;
import org.springframework.grpc.server.service.GrpcService;
// .proto에서 생성된 HelloWorldImplBase를 상속하고 @GrpcService로 등록한다
@GrpcService
public class GreeterService extends HelloWorldGrpc.HelloWorldImplBase {
@Override
public void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {
HelloReply reply = HelloReply.newBuilder()
.setMessage("Hello " + request.getName())
.build();
responseObserver.onNext(reply); // 응답 전송
responseObserver.onCompleted(); // 스트림 종료
}
}Java위 코드는 proto 파일에서 생성된 HelloWorldImplBase를 상속해 실제 gRPC 서비스 로직을 구현한 것이다. @GrpcService로 빈을 등록하면 Spring gRPC가 BindableService를 구현한 이 빈을 스캔해 서버에 자동 바인딩하므로, 별도의 서버 등록 코드가 필요 없다. 모든 .proto 생성 클래스가 BindableService를 구현하기 때문에 가능한 동작이다. 기본 포트는 9090이며 spring.grpc.server.port로 변경할 수 있다. 자세한 사용법은 Spring Boot 4.1 gRPC 레퍼런스에 나와 있다.
Jackson을 프로퍼티로 길들이는 법
Spring Boot 4.1은 Jackson의 포맷 공통 읽기·쓰기 기능을 spring.jackson.read.*와 spring.jackson.write.* 프로퍼티로 노출한다. 각각 Jackson의 StreamReadFeature와 StreamWriteFeature에 매핑되며, JSON뿐 아니라 XML·CBOR 매퍼에도 한 번에 적용된다. 이전에는 매퍼별로 커스터마이저 빈을 따로 손봐야 했던 저수준 스트리밍 옵션을 설정 파일에서 통일해 다룰 수 있게 됐다.
spring:
jackson:
write:
write-bigdecimal-as-plain: true # BigDecimal을 지수 표기 없이 일반 표기로 출력
read:
ignore-undefined: false # 정의되지 않은 토큰을 만나면 무시하지 않음YAML위 설정은 포맷에 무관한 스트리밍 레벨 동작을 프로퍼티만으로 제어하는 예시다. write-bigdecimal-as-plain은 StreamWriteFeature.WRITE_BIGDECIMAL_AS_PLAIN에, ignore-undefined는 StreamReadFeature.IGNORE_UNDEFINED에 대응한다. 주의할 점은 이 네임스페이스가 SerializationFeature나 DeserializationFeature를 대체하지는 않는다는 것이다. 날짜를 타임스탬프로 쓸지(write-dates-as-timestamps)나 미정의 필드에서 실패할지(fail-on-unknown-properties) 같은 옵션은 여전히 spring.jackson.serialization.*, spring.jackson.deserialization.*에 남아 있다. 여기에 4.1은 자동 구성 매퍼에 HandlerInstantiator를 적용해, 커스텀 serializer/deserializer를 스프링 빈으로 주입받을 수 있게 만들었고, spring.jackson.factory.*로 read/write 제약(constraint)까지 세밀하게 조정할 수 있다.
HTTP 클라이언트가 SSRF를 막기 시작했다

Spring Boot 4.1은 HTTP 클라이언트에 SSRF(Server-Side Request Forgery) 방어 장치를 내장했다. 새로 추가된 InetAddressFilter를 사용하면 내부망 대역이나 특정 주소로의 요청을 클라이언트 레벨에서 차단할 수 있다. 사용자 입력으로 URL을 받아 서버가 대신 호출하는 프록시·웹훅 검증 시나리오에서 실수로 내부 리소스를 건드리는 사고를 예방한다.
import org.springframework.boot.http.client.InetAddressFilter;
@Bean
InetAddressFilter ssrfFilter() {
// 공인 IP만 허용 — 루프백·사설 대역·클라우드 메타데이터(169.254.169.254)를 차단한다
return InetAddressFilter.externalAddresses();
}Java위 코드는 공인 주소로 나가는 요청만 허용하는 필터를 등록한 예시다. InetAddressFilter 빈을 하나만 선언하면 자동 구성된 RestClient, WebClient 등 모든 HTTP 클라이언트에 일괄 적용되며, 차단 대상 주소로의 요청은 네트워크로 나가기 전에 FilteredHostException으로 실패한다. externalAddresses()는 루프백과 사설 대역은 물론, SSRF 공격의 단골 표적인 클라우드 메타데이터 엔드포인트 169.254.169.254까지 막아준다. 특정 대역만 허용하려면 InetAddressFilter.of("10.0.0.0/8").andNot("10.0.0.1")처럼 CIDR과 논리 연산을 조합할 수 있다. 함께 추가된 쿠키 핸들링 기능도 눈여겨볼 만한데, spring.http.clients.cookie-handling 프로퍼티나 RestTemplateBuilder, 테스트 코드에서는 TestRestTemplate.withCookieHandling()으로 세션 쿠키 유지 동작을 명시적으로 제어할 수 있다.
@Async 구간에서도 트레이스가 끊기지 않는다

Spring Boot 4.1은 Observability를 강화해 @Async 메서드로 넘어가도 관측 컨텍스트가 전파되도록 개선했다. 이전에는 비동기 경계를 넘으면 traceId가 끊겨 분산 추적이 조각나는 일이 잦았는데, 4.1은 이 구간의 컨텍스트 전파를 자동 구성한다. 여기에 Kafka·RabbitMQ 컴포넌트의 observation convention이 자동 등록되고, OpenTelemetry 샘플러 설정도 새로 노출됐다.
management:
opentelemetry:
enabled: true # OpenTelemetry SDK 자동 구성 (4.1 신규 토글)
tracing:
sampling:
probability: 0.1 # 전체 트레이스의 10%만 수집YAML위 설정은 OpenTelemetry SDK를 켜고 샘플링 비율을 지정한 예시다. 4.1에서 새로 추가된 management.opentelemetry.enabled 토글로 SDK 자동 구성을 껐다 켤 수 있고, management.tracing.sampling.probability로 수집 비율을 조절한다. 여기에 management.opentelemetry.tracing.sampler로 SDK 샘플러 자체를 직접 지정하는 경로도 새로 열렸다. 전량 수집이 부담스러운 고트래픽 서비스에서 비율 샘플링으로 관측 비용을 조절할 수 있다. @Async 컨텍스트 전파는 별도 설정 없이 기본 동작하므로, 스레드 풀을 넘나드는 비동기 로직이 많은 서비스일수록 이 릴리스의 이점을 크게 본다. OTLP exemplar와 익스포터 SSL 번들 지원도 함께 추가돼, 관측 데이터를 외부 백엔드로 안전하게 내보내는 설정이 줄었다.
커넥션을 늦게 잡아 풀을 아끼는 법

Spring Boot 4.1은 spring.datasource.connection-fetch=lazy 프로퍼티로 JDBC 커넥션을 지연 획득하는 옵션을 추가했다. 이 값을 lazy로 설정하면 자동 구성된 풀 데이터소스를 LazyConnectionDataSourceProxy로 감싸, 실제 SQL이 실행되는 시점에야 물리 커넥션을 풀에서 꺼낸다. 캐시에서 조기 반환되거나 DB를 건드리지 않고 끝나는 요청이 많은 혼합 워크로드에서 풀 경합을 줄여준다.
spring:
datasource:
connection-fetch: lazy # SQL 실행 시점까지 커넥션 획득을 미룬다 (기본값: eager)YAML위 한 줄이 트랜잭션 시작만으로 커넥션을 선점하던 기존 동작을 바꾼다. @Transactional 메서드가 실제로는 캐시 히트로 조기 종료되는 경우, 기존에는 불필요하게 커넥션을 잡고 있었지만 lazy 모드에서는 그 시간을 없앤다. 짧은 트랜잭션이 대량으로 발생하는 서비스라면 커넥션 보유 시간이 줄어 풀 크기 대비 처리량이 개선된다. 다만 커넥션 획득 실패 시점이 뒤로 밀리므로, 장애 감지 위치가 달라진다는 점은 감안해야 한다. 기존 동작이 필요하면 eager로 되돌리면 된다. 이 기능의 배경은 LazyConnectionDataSourceProxy 문서에서 확인할 수 있다.
4.1로 올리기 전에 알아야 할 것들

Spring Boot 4.1로 업그레이드하기 전에 몇 가지 제거·폐기 항목을 반드시 점검해야 한다. 가장 주의할 부분은 layertools jar 모드 제거와 Derby 지원 폐기, 그리고 빌드 도구의 AOT 처리 변화다. 대부분 대체 수단이 명확하지만, 빌드 스크립트나 컨테이너 이미지 파이프라인을 건드리는 변경이라 배포 단계에서 문제가 드러나기 쉽다.
주요 변경 사항은 다음과 같다. Derby는 프로젝트 자체가 종료되면서 deprecated 처리됐으므로 H2나 HSQLDB로 이전해야 한다. 실행 가능한 jar를 다루던 layertools jar 모드는 제거됐고 tools 방식으로 대체됐다. Maven에서 -DskipTests는 더 이상 AOT 처리를 건너뛰지 않으므로, AOT까지 건너뛰려면 maven.test.skip을 써야 한다. Devtools의 LiveReload 기능도 대체 없이 deprecated됐다.
바인딩 동작에도 미묘한 변화가 있다. Optional 파라미터가 이제 null 대신 Optional.empty()로 바인딩되고, 빈 YAML 객체가 PropertySource에 유지된다. 또한 jOOQ 3.21이 Java 21을 요구하므로 런타임 JDK 버전을 함께 확인해야 한다. 자세한 목록은 Spring Boot 4.1 릴리즈 노트를 참고하면 된다.
FAQ
Spring Boot 4.1로 올리려면 Java 몇 버전이 필요한가?
Spring Boot 4.x의 베이스라인은 Java 17이지만, 4.1에서 jOOQ 3.21 등 일부 의존성이 Java 21 이상을 요구한다. jOOQ를 쓰지 않으면 Java 17로도 동작하지만, 신규 프로젝트라면 처음부터 Java 21 이상을 기준으로 잡는 편이 안전하다.
Spring Boot 4.1의 gRPC 지원은 기존 서드파티 스타터를 대체하나?
그렇다. spring-boot-starter-grpc-server가 공식 제공되면서 LogNet이나 yidongnan 스타터 없이도 gRPC 서버를 구성할 수 있다. BindableService를 구현한 빈을 등록하면 자동으로 서버에 바인딩되며, 서블릿 통합과 Netty 독립 서버를 모두 지원한다.
connection-fetch=lazy를 켜면 항상 성능이 좋아지나?
항상은 아니다. 캐시 히트나 조기 반환으로 DB를 건드리지 않는 요청이 많은 혼합 워크로드에서 커넥션 보유 시간을 줄여 이점이 크다. 반대로 거의 모든 요청이 DB에 접근한다면 프록시 오버헤드만 늘 수 있으므로, 워크로드 특성을 측정한 뒤 적용하는 것이 좋다.
Spring Boot 4.0에서 4.1로 바로 올려도 되나?
대부분 하위 호환되므로 큰 무리는 없다. 다만 layertools jar 모드 제거, Derby 폐기, -DskipTests의 AOT 동작 변경처럼 빌드·배포 파이프라인에 영향을 주는 항목이 있으므로, 스테이징 환경에서 컨테이너 이미지 빌드와 통합 테스트를 먼저 검증한 뒤 프로덕션에 반영해야 한다.
Jackson 설정을 프로퍼티로 옮기면 기존 ObjectMapper 커스터마이징은 어떻게 되나?
spring.jackson.read.* / write.* 프로퍼티는 기존 커스터마이징과 공존한다. 단순한 feature 토글은 프로퍼티로 옮기고, 복잡한 로직은 Jackson2ObjectMapperBuilderCustomizer나 팩토리 커스터마이저 빈으로 유지하면 된다. 프로퍼티 설정이 우선 적용되므로 중복 설정 시 동작을 확인해야 한다.
마치며

지금까지 Spring Boot 4.1 신기능에 대해서 정리해 보았다. 개인적으로 가장 반가운 건 connection-fetch=lazy 옵션이다. 예전에 캐시 레이어를 앞단에 둔 서비스에서 트랜잭션은 열리는데 정작 DB는 안 타는 경로가 커넥션을 붙잡고 있어, 풀을 억지로 키우며 버틴 기억이 있다. 그때 LazyConnectionDataSourceProxy를 수동으로 감싸느라 설정이 지저분해졌는데, 이제 프로퍼티 한 줄로 끝난다니 그 시절이 떠오른다. gRPC 스타터 표준화도 그동안 서드파티 스타터 버전 맞추느라 씨름하던 입장에서는 확실히 정리되는 느낌이다. 업그레이드는 늘 그렇듯 빌드·배포 파이프라인부터 조용히 깨지니, 스테이징에서 이미지 빌드 한 번 돌려보고 넘어가길 권한다.
