Contents
see ListSpring Boot 3.5 소개
Spring Boot 3.5(2026년 최신 안정 버전)는 Java 21+의 가상 스레드 지원 강화, 구조적 로깅, 개선된 SSL 설정 등 운영 환경에서 바로 활용할 수 있는 기능들을 담고 있습니다. Java 17 이상이 필요하며 Java 21 이상을 권장합니다.
1. Virtual Threads 통합 설정
Spring Boot 3.2부터 지원된 가상 스레드가 3.5에서 더욱 안정적으로 통합되었습니다.
# application.yml
spring:
threads:
virtual:
enabled: true # 이 한 줄로 Tomcat + @Async 모두 가상 스레드 활성화
// build.gradle
plugins {
id "org.springframework.boot" version "3.5.5"
id "io.spring.dependency-management" version "1.1.7"
id "java"
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}
dependencies {
implementation "org.springframework.boot:spring-boot-starter-web"
implementation "org.springframework.boot:spring-boot-starter-data-jpa"
implementation "org.springframework.boot:spring-boot-starter-actuator"
implementation "org.springframework.boot:spring-boot-starter-security"
}
// @Async도 자동으로 가상 스레드 사용
@Service
public class EmailService {
@Async
public CompletableFuture sendEmail(String to, String subject, String body) {
// spring.threads.virtual.enabled=true 설정 시 가상 스레드에서 실행
emailClient.send(to, subject, body); // 블로킹 I/O OK
return CompletableFuture.completedFuture(null);
}
}
2. Structured Logging (구조적 로깅)
Spring Boot 3.4에서 도입된 구조적 로깅이 3.5에서 더욱 강화되었습니다. JSON 형식 로그를 ELK Stack, Grafana Loki 등과 바로 연동할 수 있습니다.
# application.yml - Logstash JSON 형식 활성화
logging:
structured:
format:
console: logstash # 콘솔에 JSON 로그
# file: ecs # 파일에 Elastic Common Schema 형식
// 구조적 로그 출력 예시
{
"@timestamp": "2026-04-13T10:30:00.123Z",
"level": "INFO",
"logger": "com.example.UserService",
"message": "사용자 로그인 성공",
"userId": "user123",
"requestId": "req-abc-456",
"duration_ms": 45
}
// 커스텀 필드 추가 - MDC 활용
@Component
public class RequestLoggingFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
String requestId = UUID.randomUUID().toString();
MDC.put("requestId", requestId);
MDC.put("userId", getCurrentUserId());
try {
chain.doFilter(req, res);
} finally {
MDC.clear(); // 반드시 정리
}
}
}
@Service
@Slf4j
public class UserService {
public User findUser(Long id) {
log.info("사용자 조회 시작", StructuredArguments.kv("userId", id));
User user = userRepository.findById(id).orElseThrow();
log.info("사용자 조회 완료"); // requestId, userId가 자동으로 포함됨
return user;
}
}
3. WebClient 글로벌 설정 (Spring Boot 3.5 신기능)
Spring Boot 3.5에서는 properties 파일로 WebClient의 전역 설정이 가능해졌습니다.
# application.yml - WebClient 글로벌 설정
spring:
webclient:
connect-timeout: 5s
read-timeout: 30s
max-in-memory-size: 10MB
// RestClient 사용 예시 (WebClient의 동기 버전)
@Configuration
public class ApiConfig {
@Bean
public RestClient githubClient(RestClient.Builder builder) {
return builder
.baseUrl("https://api.github.com")
.defaultHeader("Authorization", "Bearer " + token)
.defaultHeader("Accept", "application/vnd.github+json")
.build();
}
}
@Service
public class GithubService {
private final RestClient githubClient;
public List getUserRepos(String username) {
return githubClient.get()
.uri("/users/{username}/repos", username)
.retrieve()
.body(new ParameterizedTypeReference>() {});
}
}
4. @ConfigurationProperties 개선
// Record를 활용한 불변 설정 클래스
@ConfigurationProperties(prefix = "app.payment")
@Validated
public record PaymentProperties(
@NotBlank String apiKey,
@NotNull @Valid RetryConfig retry,
@DurationUnit(ChronoUnit.SECONDS) Duration timeout
) {
public record RetryConfig(
@Min(1) @Max(10) int maxAttempts,
@DurationUnit(ChronoUnit.MILLIS) Duration backoff
) {}
}
# application.yml
app:
payment:
api-key: ${PAYMENT_API_KEY}
timeout: 30s
retry:
max-attempts: 3
backoff: 500ms
5. Spring Security 6.x 최신 설정
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt.jwtAuthenticationConverter(jwtConverter()))
)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.csrf(csrf -> csrf.disable()) // JWT 사용 시 CSRF 비활성화
.cors(cors -> cors.configurationSource(corsConfigurationSource()));
return http.build();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOriginPatterns(List.of("https://*.example.com"));
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
config.setAllowedHeaders(List.of("*"));
config.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/api/**", config);
return source;
}
}
6. Actuator 보안 강화 (Spring Boot 3.5)
Spring Boot 3.5에서 heapdump 엔드포인트의 기본값이 access=NONE으로 변경되어 실수로 민감 정보가 노출되는 것을 방지합니다.
# application.yml - Actuator 설정
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus # 필요한 것만 노출
endpoint:
health:
show-details: when-authorized
heapdump:
access: none # 3.5 기본값 - 명시적으로 허용하지 않으면 비활성화
server:
port: 8081 # 별도 포트로 분리 (운영 환경 권장)
마치며
Spring Boot 3.5는 운영 환경에서의 안정성과 관측 가능성(Observability)을 크게 강화했습니다. 가상 스레드 설정 한 줄로 Tomcat의 처리량을 대폭 높이고, 구조적 로깅으로 운영 모니터링을 체계화할 수 있습니다.