Back-End/Spring-Boot 7

스프링 부트 GC 로그 해석 실전 — Metadata GC Threshold로 Full GC가 길어질 때

운영 중 서비스가 갑자기 멈춘 듯 느려지고, 모니터링에 긴 스파이크가 찍히는 순간이 있다. 이럴 때 GC 로그는 원인을 추정이 아닌 증거로 보여준다. 특히 다음과 같은 문구가 보인다면 메타스페이스(Metaspace)가 범인일 가능성이 높다.Pause Full (Metadata GC Threshold) 214M->214M(2048M) 43012.7ms이번 글은 이 한 줄을 어디까지 읽어낼 수 있는지, 그리고 실제로 무엇을 확인하고 어떻게 조치하는지 단계별로 정리한다.1) 샘플 로그와 한 줄 해석다음은 실제 운영에서 캡처한 패턴을 단순화한 예시다. (Java 11, G1GC, unified logging)[2.431s][info][gc] GC(365) Pause Young (Concurrent Start) ..

Mono 고급 정리 - zip, fromCallable, block까지 실전 활용 정리

이전 글에서 Mono의 기본 생성 방식과 연산자들 (flatMap, map, switchIfEmpty 등)을 정리했었다.이번에는 한 단계 더 나아가서, 실무에서 자주 마주치는 상황에서 어떻게 Mono를 응용할 수 있을지 다뤄보자. 1. Mono.zip() - 여러 Mono를 병렬로 실행하고 결과를 합칠 때zip()은 두 개 이상의 Mono를 동시에 실행해서, 결과를 묶어서 처리할 수 있게 해준다.(모든 Mono가 완료되기 전까지는 실행되지 않음)예제: 사용자 정보와 포인트 정보를 동시에 가져오기Mono userMono = userRepository.findById("123");Mono pointMono = pointService.getPointByUserId("123");Mono> zipped = Mon..

Spring WebFlux의 Mono

Spring WebFlux를 처음 시작하면 가장 먼저 마주치는 게 바로 Mono와 Flux다.이 중 Mono는 "0 또는 1개의 데이터를 비동기적으로 처리하는 Publisher"다.한 줄 요약: Mono는 '1개의 데이터 또는 아무 것도 없는' 비동기 데이터 그릇이다. 왜 Mono를 써야 할까?전통적인 Spring MVC에서는 메서드가 값을 리턴하면, 그 값은 동기적으로 바로 반환된다.하지만 WebFlux는 Reactive Streams 기반으로 동작하기 때문에, Mono를 통해 데이터를 "나중에", "비동기로", "필요할 때" 처리한다.@GetMapping("/user/{id}")public Mono getUser(@PathVariable String id) { return userReposito..

DTO ↔ Entity 변환에 대한 고민과 MapStruct

DTO Entity 변환에 대한 고민과 MapStruct스프링 부트를 사용하면서 DTO와 Entity의 책임을 분리하다 보면, 변환 과정에서 코드가 점점 복잡해진다.처음에는 get/set을 직접 사용해서 변환했지만, 필드가 많아질수록 코드가 길어지고 유지보수가 어려워졌다.이 고민 끝에 MapStruct를 도입해 보았다.MapStruct는 DTO ↔ Entity 변환을 자동화해주면서도 성능이 뛰어나고 유지보수가 쉬운 라이브러리다.이 글에서는 DTO와 Entity 변환에 대한 고민을 정리하고, MapStruct를 어떻게 활용할 수 있는지 살펴보려고 한다. 1. DTO ↔ Entity 변환이 복잡해지는 이유JPA를 사용하면서 DTO와 Entity를 분리하는 이유는 명확하다.Entity는 데이터베이스와 직접 ..

JPA에서 JPQL 사용하는 법

JPA에서 JPQL 사용하는 법JPA를 쓰다 보면 단순히 findById 같은 기본 메서드로는 해결이 안 되는 경우가 많다. 이럴 때 JPQL을 활용하면 더 유연하게 데이터를 가져올 수 있다. SQL이랑 비슷하지만, 테이블이 아니라 엔티티 기준으로 작성한다는 게 핵심. 1. 기본적인 JPQL 쿼리@Query("SELECT u FROM UserInfo u WHERE u.clientCode = :clientCode")UserInfo findByClientCode(@Param("clientCode") String clientCode);UserInfo 엔티티에서 clientCode가 특정 값인 데이터를 가져온다.테이블이 아니라 엔티티 이름을 기준으로 조회해야 한다.:clientCode는 파라미터 바인딩. 2. ..

파라미터 포맷 변환(String -> LocalDateTime)

Vue로부터 Stirng으로 받아온 날짜 파라미터를 변환 @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) 어노테이션을 사용하면, Spring이 String을 LocalDate로 자동 변환해 줍니다.1. Spring이 변환하는 과정@GetMapping("/api/data")public List getData( @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate targetDate) { System.out.println("Received targetDate: " + targetDate);} 클라이언트에서 YYYY-MM-DD 형식의 문자열을 전송:GET /api/data?targetDate..

Response Body 객체 기본생성자

@RequestBody에 매핑되는 객체는 기본적으로 기본 생성자를 사용해서 생성됩니다.이 과정은 Jackson 라이브러리가 JSON 데이터를 자바 객체로 변환할 때 자동으로 이루어집니다.기본 생성자 사용@RequestBody로 받은 데이터를 변환하려면 객체가 기본 생성자를 갖고 있어야 합니다. 즉, Jackson은 기본 생성자를 호출하여 객체를 생성한 뒤, 그 후 필드들을 setter 메서드나 필드 접근을 통해 값을 설정합니다.예를 들어, 다음과 같은 DTO 클래스가 있을 때:public class MyDto { private String userId; private String no; // 기본 생성자 public MyDto() { } // Getter와 Setter ..