각 문제 상황은 실제 웹 서비스 운영에서 자주 발생하는 대표적인 오류 유형이다. 입력 검증 실패, 예외 처리 부족, 자원 고갈, 외부 연동 장애 등은 서비스 안정성과 신뢰성을 저하시킬 수 있다.
| 구분 | 개념 | 설명 |
|---|---|---|
| 잘못된 입력값 유입 | 사용자가 의도적·비의도적으로 유효하지 않은 데이터를 전송하는 상황 | 형식 오류, 범위 초과 등으로 인해 애플리케이션이 정상적으로 동작하지 않는 상황 |
| 예상치 못한 예외 발생 | 코드에서 처리되지 않은 런타임 오류가 발생하는 상황 | NullPointer, DB 연결 오류 등으로 서비스 로직이 중단되는 상황 |
| 시스템 리소스 부족 | CPU·메모리·디스크·네트워크 등 한정된 자원이 초과 사용되는 상황 | 자원 고갈로 응답 지연이나 장애가 발생하는 상황 |
| 외부 시스템 연동 실패 | 결제·인증·제3자 API 등 외부 서비스와의 통신 오류 | 요청 실패 또는 지연으로 내부 서비스까지 영향이 전파되는 상황 |
사용자가 의도적· 비의도적으로 유효하지 않은 데이터(형식 오류, 범위 초과 등)를 전송하여 애플리케이션이 정상적으로 동작하지 않는 상황이다. 일반적으로 프론트엔드에서 입력값을 검증하고 차단하지만, 보안과 안정성을 위해 백엔드 애플리케이션 계층이나 데이터베이스 계층에서도 유효성 검증을 수행하여 잘못된 데이터의 저장 및 처리를 방지할 수 있다.
| 패턴 | 설명 | 대응 방안 |
|---|---|---|
| 사용자 실수 | 오타, 필수값 누락, 잘못된 형식 | 프론트 검증(필수 체크·형식 안내) + 백엔드/DB 제약(Bean Validation, UNIQUE/CHECK) |
| SQL 인젝션 / 스크립트 주입 | 악성 코드 삽입으로 정보 유출·변조 | 파라미터 바인딩(PreparedStatement/ORM), 입력 패턴 검사, 출력 이스케이프(HTML/JS) |
| 범위 초과 입력 | 음수, 과도한 수치 등 비정상 값 입력 | 입력 제한(최소·최대), 유효성 검사(@Min/@Max, DB CHECK 제약) |
| 중복 요청 | 결제·주문 중복 처리 발생 | 멱등 키(토큰), 유니크 제약, 서버 측 중복 방지 락/디듀프 |
| 스키마 불일치 | 필드 누락·타입 오류 | 스키마 검증(JSON Schema/OpenAPI), 타입 제약(요청 DTO 검증) |
코드에서 처리되지 않은 런타임 오류(NullPointer, DB 연결 오류 등)가 발생해 서비스 로직이 중단되는 상황
예외는 프로그래밍 상으로 충분히 발생 할 수 있지만, 이러한 예외를 사용자에게 노출한 경우 보안 위협이 발생 할 수 있음으로 일관성 있는 예외 처리가 필요하다.
CPU, 메모리, 디스크, 네트워크 등 한정된 자원이 초과 사용되어 응답 지연이나 장애가 발생하는 상황
→ 초반 성능 테스트 이후 충분한 HW가 보장된다 할지라도 프로그램 에러나 HW 고장으로 발생 할 수 있는 요소
운영 모니터링 및 복원력(Resilience) 향상으로 대응 가능
| 구분 | 설명 | 대응 방안 |
|---|---|---|
| CPU 과부하 | 무한 루프, 비효율적 연산, 대량 요청으로 처리 지연 발생 | 효율적 알고리즘 적용, 스레드풀/큐 크기 제한, 서버 확장(오토스케일링) |
| 메모리 부족 | 객체 누수, 캐시 남용, 대용량 적재로 OOM 발생 | 누수 점검(프로파일링), 캐시 용량·TTL 제한, 스트리밍 처리, GC 튜닝/힙 조정 |
| 디스크 부족/과다 I/O | 로그 폭증, 대용량 파일, 인덱스 부재로 성능 저하 | 로그 로테이션, 불필요 데이터 정리, 인덱스 최적화/리빌드 |
| 네트워크 대역폭 초과 | 접속자 폭증, 대용량 응답, DDoS로 지연 발생 | CDN, Rate Limiting, DDoS 방어(웹 방화벽), 응답 압축/캐싱 |
| 공통 대응(모니터링) | 모니터링으로 장애를 빠르게 발견·회복 | Spring Boot Actuator(health/metrics), 외부 모니터링 연동(ELK/Grafana/Prometheus), Amazon CloudWatch 연동 |
결제, 인증, 제3자 API 등 외부 서비스와 통신 오류가 발생하여 요청이 실패하거나 지연되는 상황이다.
일반적으로 Resilience4j를 통한 복원력 강화로 해결 가능하다.
| 구분 | 설명 | 대응 방안 |
|---|---|---|
| 타임아웃 관리 | 외부 서비스 응답 지연으로 호출이 길어지는 상황 | 요청 타임아웃 설정(연결/읽기 분리), 빠른 실패 처리(취소·정리 로직) |
| 재시도 + 백오프 | 일시적 오류로 호출 실패 | 지수 백오프 재시도, 재시도 횟수 제한, 대상 한정(5xx/네트워크 오류만) |
| 회로 차단 (Circuit Breaker) | 외부 장애가 연속 발생해 내부로 전파 | 실패율·슬로우율 기준 차단, 열림→반열림→닫힘 전이, 차단 중 즉시 실패 |
| 폴백 (Fallback) | 외부 의존성 문제로 기능이 중단 | 캐시/기본값 반환, 대체 경로 안내, 사용자 친화 오류 메시지 제공 |
| 구분 | 설명 | 활용 도구 |
|---|---|---|
| 예외 처리 | 런타임 오류 발생 시 서비스 중단을 방지하고 사용자 친화적 응답 제공 | @ControllerAdvice, @ExceptionHandler |
| 로깅 | 실행 흐름과 오류를 기록하여 원인 분석·추적 지원 | SLF4J, Logback, Log4j2 |
| 입력값 검증 | 잘못된 데이터 유입 차단으로 보안·안정성 강화 | Bean Validation(JSR-380), @Valid, @NotNull, @Size |
| 모니터링 | 상태·성능·리소스 사용량 관찰로 장애 조기 탐지 | Spring Boot Actuator, Micrometer, Prometheus, Grafana |
예외처리는 실행 중 발생할 수 있는 비정상 상황(에러나 오류)을 정상적으로 제어하기 위한 기법이다.
에러를 무시하거나 프로그램이 중단되지 않도록 하고, 사용자에게 의미 있는 응답을 제공할 수 있도록 한다. Java에서는 try-catch-finally 구문이나 throw/throws 키워드를 통해 예외를 명시적으로 처리한다.
public class ExceptionExample {
public static void main(String[] args) {
try {
int result = 10 / 0; // 예외 발생 코드
System.out.println("결과: " + result);
} catch (ArithmeticException e) {
System.out.println("예외 발생: " + e.getMessage());
e.printStackTrace();
} finally {
System.out.println("프로그램 종료");
}
}
}
| 구분 | 내용 | 활용 기술 |
|---|---|---|
| 안정적인 서비스 운영 | 전역 예외 처리로 컨트롤러 단의 오류를 일관되게 흡수하여 서비스 중단 방지 | @ControllerAdvice, @ExceptionHandler, ResponseEntityExceptionHandler, HandlerExceptionResolver |
| 사용자 피드백 제공 | 상태코드·메시지·에러코드·필드 오류를 구조화해 이해 가능한 응답 제공 | @ResponseStatus, 표준 오류 응답 스펙 설계 |
| 시스템 장애 예방 및 추적 | 요청 단위 추적·징후 모니터링, 서킷브레이커·재시도로 장애 전파 차단 및 원인 추적 | 로깅(Logback), Actuator, Resilience4j |
| 디버깅 정보 수집 | 검증/서버 예외 메타데이터, 요청·응답 페이로드, 사용자·트레이스 정보 기록으로 재현성 향상 | 로깅(Logback), 커스텀 에러, Actuator |
Spring의 예외 처리 아키텍처는 DispatcherServlet이 컨트롤러 실행 중 발생한 예외를 받아 HandlerExceptionResolver 체인에 위임하고, 적절한 리졸버가 예외를 처리하여 ModelAndView나 응답을 반환하는 구조로 구성되어 있다.
만일, 에러체인이 적용되어 있지 않은 경우 DispatcherServlet이 WAS(Tomcat)으로 전파하여 WAS가 에러처리를 수행한다.
ExceptionHandlerExceptionResolver는 @ExceptionHandler 메서드와 @ControllerAdvice나 @RestControllerAdvice에 등록된 전역 핸들러를 탐색해 실행한다. 즉, Resolver가 예외를 가로채고 Advice가 전역 예외 처리 메서드를 제공하여 일관된 예외 응답을 가능하게 한다.
HandlerExceptionResolver: 예외를 가로채어 알맞은 핸들러(@ExceptionHandler)나 기본 전략으로 변환하는 처리기Spring Boot에서는 데이터 접근 기술과 무관하게 일관된 예외 계층(DataAccessException)으로 처리할 수 있다.
DB 벤더나 기술별 예외를 추상화하여 코드 변경 없이 동일한 로직으로 대응 가능하다.
예외 성격(일시적/영구적)을 구분해 재시도, 사용자 메시지, 로깅 정책을 체계적으로 적용할 수 있다.
Exception과 Error 클래스 모두 Object 클래스의 자손이며 모든 예외의 최고 조상은 Exception 클래스
반드시 예외 처리해야 하는 Checked Exception과 해주지 않아도 되는 Unchecked Exception으로 나뉨
| 오류 클래스 | 설명 |
|---|---|
| OutOfMemoryError | JVM 힙 메모리가 부족할 때 발생 |
| StackOverflowError | 재귀 호출이 너무 깊어 스택이 넘칠 때 발생 |
| VirtualMachineError | JVM이 내부적으로 심각한 문제를 만났을 때(치명적 오류의 상위 클래스) |
| NoClassDefFoundError | 컴파일은 성공했지만 실행 중 클래스 로딩 실패(클래스패스 누락/초기화 실패 등) |
| InternalError | JVM 내부 버그로 인해 발생하는 오류 |
| 예외 클래스 | 설명 |
|---|---|
| IOException | 입출력 작업 중 오류(파일, 네트워크 스트림 등) |
| FileNotFoundException | 존재하지 않는 파일을 열거나 접근할 때 발생 (IOException 하위) |
| SQLException | DB 연결·쿼리 실행 등 JDBC 작업 중 오류 |
| ParseException | 문자열 파싱 실패(날짜/숫자/커스텀 포맷 등) |
| ClassNotFoundException | Class.forName() 등으로 클래스 로딩 실패(컴파일 성공 → 런타임 클래스패스 문제) |
| InterruptedException | 대기/슬립/블로킹 중인 스레드가 인터럽트될 때 발생 |
| MalformedURLException | 잘못된 URL 형식(프로토콜/포맷 오류) (IOException 하위) |
| 예외 클래스 | 설명 |
|---|---|
| NullPointerException | null 참조에 접근(메서드 호출, 필드 접근, 언박싱 등)할 때 발생 |
| ArrayIndexOutOfBoundsException | 배열 인덱스가 범위를 벗어날 때(음수 또는 length 이상) 발생 (IndexOutOfBoundsException 하위) |
| IndexOutOfBoundsException | 리스트/문자열 등에서 유효 범위를 초과한 인덱스 접근 시 발생 |
| ArithmeticException | 0으로 나누기 등 산술 연산 오류 발생 |
| IllegalArgumentException | 메서드에 부적절한 인자 전달 시 발생 (NumberFormatException 포함) |
| IllegalStateException | 객체의 현재 상태가 메서드 호출에 부적합할 때 발생 |
| ClassCastException | 호환되지 않는 타입으로 형변환 시 발생 |
| NumberFormatException | 숫자가 아닌 문자열을 숫자로 파싱할 때 발생 (IllegalArgumentException 하위) |
| UnsupportedOperationException | 지원되지 않는 기능을 호출할 때 발생(예: 불변 컬렉션 수정 시) |
| ConcurrentModificationException | 반복 중 컬렉션을 구조적으로 변경할 때 발생(FAIL-FAST 이터레이터) |
| 예외 클래스 | 설명 |
|---|---|
| DataAccessException | 데이터 접근 계층에서 발생하는 모든 예외의 루트 클래스 |
| CleanupFailureDataAccessException | 리소스 정리(clean-up) 과정에서 오류 발생 시 |
| DataIntegrityViolationException | 데이터 무결성 제약 조건 위반 시(UNIQUE, FK 등) |
| DataRetrievalFailureException | 특정 데이터 조회 실패 시 |
| DeadlockLoserDataAccessException | DB 데드락으로 인해 현재 트랜잭션 실패 시 |
| IncorrectResultSizeDataAccessException | 예상한 결과 개수와 다른 경우(예: 단일 조회인데 여러 건 반환) |
| IncorrectUpdateSemanticsDataAccessException | 잘못된 Update 실행 결과 발생 시 |
| InvalidDataAccessApiUsageException | 잘못된 DAO API 사용 시 |
| InvalidDataAccessResourceUsageException | 잘못된 리소스 사용 시(잘못된 SQL 구문 등) |
| PermissionDeniedDataAccessException | 접근 권한이 없어 실행 불가 시 |
| TransientDataAccessException | 일시적인 예외 발생(재시도 가능) |
| QueryTimeoutException | 쿼리 실행 시간 초과 시 |
| TypeMismatchDataAccessException | JDBC 타입 불일치 시 |
| UncategorizedDataAccessException | 분류되지 않은 기타 데이터 접근 예외 |
예외 변환 메커니즘은 하위 계층에서 발생한 기술 종속적인 예외를 상위 계층에서 이해할 수 있는 추상화된 예외로 변환하는 과정이다. 이를 통해 DB, 네트워크 등 다양한 자원 예외를 일관된 방식으로 처리하고, 서비스·컨트롤러 계층에서는 표준화된 예외 처리 로직만 유지하면 된다.즉, 내부 구현 변경에도 불구하고 외부 계층은 동일한 예외 처리 계약을 사용할 수 있게 한다.
1) @RestControllerAdvice 활용
2) 일관된 오류 응답 구조 설계
로깅(Logging)은 애플리케이션 동작 과정에서 발생하는 다양한 이벤트, 상태, 오류 정보를 기록하는 행위이다.
운영 중 문제 원인을 추적하고 성능을 분석하며 보안· 감사를 위해 필수적인 근거 자료를 제공한다.
이를 통해 개발자는 디버깅, 모니터링, 장애 대응을 효과적으로 수행할 수 있다.
| 구분 | 설명 | 사용 환경 | 권장 여부 |
|---|---|---|---|
| SLF4J (Facade) | 로깅 추상화 계층. 구현체(Logback·Log4j2 등)를 유연하게 교체 가능 | 모든 Spring Boot 프로젝트의 표준 로깅 API | 필수 |
| Logback | Spring Boot 기본 구현체. 설정 간단, 성능 우수 | 일반 웹/마이크로서비스, 대부분의 서비스 | 권장 |
| Log4j 2 | Log4j 개선판. 비동기 로깅(Async) 지원, 다양한 설정(XML/YAML/JSON) | 고부하·대규모 트래픽, 실시간 스트리밍 | 조건부 권장 (고성능 요구 시) |
| Log4j 1.x | 과거 많이 사용. 현재 EOL(지원 종료)로 보안 취약점 존재 | 레거시 시스템 유지보수 목적 | 비권장 (신규 사용 금지) |
| java.util.logging (JUL) | JDK 기본 로깅. 단순하지만 기능 제한 | 레거시 통합, 경량 환경 | 비권장 |
| 구분 | 설명 |
|---|---|
| 애플리케이션 동작 상태 파악 | 시스템의 정상 동작 여부, 성능 지표, 서비스 처리 흐름을 기록하여 운영자가 상태를 실시간으로 파악할 수 있게 함 |
| 문제 상황 분석과 해결 | 오류·예외 발생 시 로그로 원인을 추적해 디버깅 및 문제 해결 시간을 단축함 |
| 비즈니스 이벤트 추적 | 사용자 활동, 주문 처리, 결제 내역 등 비즈니스 단위 이벤트를 기록해 품질 관리와 데이터 분석에 활용함 |
| 보안 감사(Audit) | 접근 이력, 권한 변경, 민감 정보 접근 등을 기록해 보안 침해 탐지와 컴플라이언스 준수에 활용함 |
%d{yyyy-MM-dd HH:mm:ss.SSS} : 날짜/시간
%-5level : 로그 레벨 (고정 길이 5칸)
%thread : 스레드명
%logger{36} : 로거명(클래스명), 최대 36자
%msg : 로그 메시지logging.file.name: 로그 파일 이름 지정
logging.file.path: 디렉토리 지정 (기본 파일명은 spring.log)| 구분 | 개발 환경(Development) | 운영 환경(Production) |
|---|---|---|
| 출력 대상 | 콘솔 중심 (Logback/Log4j) | 파일 로그 + 외부 수집 시스템(ELK, Grafana, Prometheus) |
| 로그 레벨 | DEBUG 또는 TRACE (상세 정보 포함) | INFO 또는 WARN 이상 (필요 최소한) |
| 로그 관리 | 짧은 주기로 롤링, 불필요한 공간 낭비 방지 | 용량/기간 기반 롤링, 장기 보관 정책 적용 |
| 활용 목적 | 디버깅 편의성, 문제 원인 빠른 진단 | 성능 최적화, 보안 감사, 운영 안정성 |
| Spring Boot 설정 | application-dev.yml | application-prod.yml |
| 로그 레벨 | 목적 | 사용 시점 |
|---|---|---|
| TRACE | 가장 상세한 로그, 내부 흐름을 단계별로 추적 | 메서드 진입/반환, 루프 내부 값 확인 등 세밀한 디버깅 상황 |
| DEBUG | 개발자가 디버깅할 때 필요한 정보 제공 | SQL 쿼리 출력, 주요 변수 값 확인, 조건 분기 결과 등 (개발 환경 전용) |
| INFO | 시스템의 정상 동작을 알리는 운영 정보 | 서비스 시작/종료, 중요한 비즈니스 이벤트(회원 가입, 주문 완료 등) |
| WARN | 잠재적 문제를 경고(즉시 장애는 아님) | Deprecated API 호출, 성능 저하 가능성, 임계치 접근 상황 |
| ERROR | 비정상 상황으로 기능 실패를 알림 | 예외 발생, DB 연결 실패, 외부 서비스 호출 실패 등 (운영 대응 필요) |
간결하고 명확하게: 로그 메시지는 한눈에 이해할 수 있도록 작성
맥락 포함: 어떤 작업 중, 어떤 데이터에 대해 발생했는지 기술
민감 정보 제외: 비밀번호, 주민등록번호, 카드번호 등은 로깅 금지
일관된 형식: 동일한 구조(Action - 대상- 결과/상태)로 작성해 분석 용이성 확보
예외 스택트레이스 출력은 반드시 ERROR 레벨에서 사용
메시지와 함께 비즈니스 컨텍스트(orderId, userId 등)를 같이 남겨야 문제 추적 용이
단순 사용자 입력 오류는 WARN, 시스템 오류(DB 연결 실패 등)는 ERROR로 구분
throw 전에 로깅하고, 불필요한 중복 로그는 피함
1) 주요 로깅 포인트
2) 로그 검색과 분석
3) 문제 해결을 위한 활용
Bean Validation은 자바 애플리케이션에서 객체의 속성 값 검증을 표준화하기 위한 스펙(JSR 380, JSR 303)이다.
어노테이션 기반으로 필드 제약 조건(@NotNull, @Size, @Email 등)을 선언하여 중복 코드 없이 일관된 검증 로직을 제공한다. Spring Boot와 통합 시 Controller, Service, Persistence 계층까지 자동 검증과 예외 처리를 지원
| 구분 | 설명 |
|---|---|
| 잘못된 데이터 유입 방지 | 유효하지 않은 값이 시스템 내부로 들어오는 것을 차단하여 오류와 보안 취약점을 예방 |
| 일관된 검증 로직 관리 | 애플리케이션 전반에서 동일한 검증 규칙을 적용해 중복 코드와 관리 비용을 줄임 |
| 비즈니스 규칙 강제 | 도메인 규칙(예: 나이 제한, 이메일 형식 등)을 코드 레벨에서 강제하여 데이터 무결성 확보 |
| 명확한 에러 메시지 제공 | 검증 실패 시 사용자에게 구체적이고 이해하기 쉬운 피드백을 제공해 문제 해결을 지원 |
| 어노테이션 | 설명 | 주 사용 위치 | 사용 예시 |
|---|---|---|---|
@Valid | JSR-303 표준 검증 트리거. 객체·중첩 객체까지 연쇄(cascaded) 검증 | Controller 파라미터, DTO 필드 | public Response create(@Valid @RequestBody UserDto dto) |
@Validated | Spring 전용. 그룹 기반 검증·메서드 레벨 검증 지원 | Controller/Service 클래스·메서드 | @Validated(Create.class) |
@NotNull | 값이 null이면 안 됨 | 필드, 파라미터 | @NotNull private String name; |
@NotEmpty | null·빈 문자열("")·빈 컬렉션 불가 | 문자열/컬렉션 필드 | @NotEmpty private List<String> items; |
@NotBlank | null·빈 문자열·공백만 있는 문자열 불가 | 문자열 필드 | @NotBlank private String title; |
@Min / @Max | 숫자 값의 최소/최대 범위 제한 | 숫자 필드 | @Min(1) @Max(100) private int age; |
@Positive / @Negative | 양수/음수만 허용 | 숫자 필드 | @Positive private Long price; / @Negative private Integer change; |
@Size | 문자열/컬렉션 길이(개수) 제한 | 문자열/컬렉션 필드 | @Size(min=2, max=20) private String nickname; |
@Email | 이메일 형식 검증 | 문자열 필드 | @Email private String email; |
@Pattern | 정규식으로 형식 검증 | 문자열 필드 | @Pattern(regexp="^[0-9]{3}-[0-9]{4}$") private String phone; |
@Past / @Future | 과거만 / 미래만 허용 | 날짜·시간 필드 | @Past private LocalDate birthday; / @Future private LocalDate dueDate; |
@PastOrPresent / @FutureOrPresent | 과거 또는 현재 / 미래 또는 현재 허용 | 날짜·시간 필드 | @FutureOrPresent private LocalDate startDate; |
커스텀 Validator는 기본 제공 검증으로 처리할 수 없는 도메인 특화 검증 규칙을 직접 정의하는 컴포넌트이다.
ConstraintValidator 인터페이스를 구현해 어노테이션과 함께 사용하며, 객체 필드나 요청 값에 대해 맞춤형 유효성 검사를 수행한다.
1) 커스텀 제약조건 정의
@Documented
@Target({ ElementType.FIELD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = StrongPasswordValidator.class)
public @interface StrongPassword {
String message() default "{error.password.strong}"; // 메시지 키
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
int min() default 8; // 커스터마이즈 가능한 속성
boolean requireUpper() default true;
boolean requireLower() default true;
boolean requireDigit() default true;
boolean requireSpecial() default true;
}
2) Validator 클래스 구현
public class StrongPasswordValidator implements ConstraintValidator<StrongPassword, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value == null || value.isBlank()) return false;
return value.length() >= 8
&& value.chars().anyMatch(Character::isUpperCase)
&& value.chars().anyMatch(Character::isLowerCase)
&& value.chars().anyMatch(Character::isDigit);
}
}
3) 검증 로직 작성(적용 & 메시지)
public record SignUpRequest(
@NotBlank(message = "이메일을 입력해 주시기 바랍니다.")
@Email(message = "올바른 이메일 주소를 입력해 주시기 바랍니다.")
String email,
@NotBlank(message = "비밀번호를 입력해 주시기 바랍니다.")
@StrongPassword(min = 10, message = "{error.password.strong}") // 메시지 키 사용
String password
) {}
1) 중첩된 객체 검증
public class Address {
@NotBlank(message = "도로명은 반드시 입력해 주셔야 합니다.")
private String street;
@NotBlank(message = "도시는 반드시 입력해 주셔야 합니다.")
private String city;
}
public class UserRequest {
@NotBlank(message = "이름은 반드시 입력해 주셔야 합니다.")
private String name;
@Valid
private Address address; // 중첩 객체도 검증
}
2) 컬렉션 요소 검증
public class OrderRequest {
@NotBlank
private String orderId;
@Size(min = 1, message = "최소 한 개 이상의 상품이 필요합니다.")
private List<@Valid ProductRequest> products; // 리스트 요소 검증
}
public class ProductRequest {
@NotBlank(message = "상품명은 비워 둘 수 없습니다.")
private String name;
@Positive(message = "가격은 양수여야 합니다.")
private int price;
}
3) 상황별 검증 전략
public class UserDto {
public interface Create {}
public interface Update {}
@NotNull(groups = Update.class, message = "수정 시에는 ID가 필요합니다.")
private Long id;
@NotBlank(groups = {Create.class, Update.class}, message = "이름은 필수 입력 값입니다.")
private String name;
}
@RestController
public class UserController {
@PostMapping("/users")
public ResponseEntity<?> create(@Validated(UserDto.Create.class) @RequestBody UserDto dto) {
...
}
@PutMapping("/users")
public ResponseEntity<?> update(@Validated(UserDto.Update.class) @RequestBody UserDto dto) {
...
}
}
Spring Boot Actuator는 애플리케이션의 상태, 메트릭, 로그, 환경 정보를 확인하고 관리할 수 있는 모니터링 도구이다. 운영 환경에서 서비스의 헬스체크, 성능 지표 수집, 모니터링 시스템 연계(Prometheus, Grafana 등)나 클라우드 자체 Watch에서 연동하여 활용된다.
| 구분 | 설명 |
|---|---|
| 실시간 상태 모니터링 | 애플리케이션·서버·네트워크의 현재 상태를 실시간으로 관찰해 성능 저하나 장애를 즉시 감지 |
| 잠재적 문제 조기 발견 | 리소스 사용량·에러 패턴을 분석해 문제가 커지기 전에 선제 대응 가능하도록 지원 |
| 주요 지표 수집과 분석 | CPU·메모리·응답 시간·트랜잭션 처리량 등 핵심 지표를 수집·분석해 성능 최적화와 용량 계획에 활용 |
| 정상 동작 여부 확인 | 구성 요소의 정상 동작을 주기적으로 점검해 서비스 가용성과 안정성을 보장 |
# build.gradle
dependencies {
implementation 'de.codecentric:spring-boot-admin-starter-client:3.4.5'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
}
# application.yml
management:
endpoints:
web:
exposure:
include: health, info, metrics, env # 활성화할 엔드포인트 목록
management.endpoint.health.show-details 옵션으로 Health 엔드포인트의 정보 노출 범위를 설정never: 항상 단순 UP/DOWN만 반환when-authorized: 인증된 사용자만 상세 정보 확인 가능always: 모든 상세 정보 노출@Component
public class CustomHealthIndicator implements HealthIndicator {
@Override
public Health health() {
boolean serverUp = checkExternalServer();
if (serverUp) {
return Health.up().withDetail("ExternalServer", "Available").build();
}
return Health.down().withDetail("ExternalServer", "Unavailable").build();
}
private boolean checkExternalServer() {
// 외부 서버 Ping 체크 로직
return true;
}
}
/actuator/info 엔드포인트를 통해 애플리케이션 버전, 빌드 정보, 개발자 정보를 제공할 수 있다.application.yml에 info.* 속성을 정의하거나, InfoContributor를 구현해 동적으로 정보 제공 가능하다.# application.yml
info:
app:
name: codeit-service
version: 1.0.0
developer:
name: Hae Lee
email: test@email.com
@Component
public class CustomInfoContributor implements InfoContributor {
@Override
public void contribute(Info.Builder builder) {
builder.withDetail("custom", Map.of("status", "running", "uptime", "1024s"));
}
}
/actuator/metrics 엔드포인트에서 CPU 사용량, JVM 메모리, HTTP 요청 수, DB 커넥션 풀 상태 등의 지표를 확인 가능하다.# 전체 메트릭 목록
GET /actuator/metrics
# 특정 메트릭 상세 조회
GET /actuator/metrics/jvm.memory.used
GET /actuator/metrics/http.server.requests
Actuator+Prometheus+Grafana 모니터링 스택으로 부르며 모니터링 방법으로 가장 많이 활용되는 아키텍처
Spring Actuator는 애플리케이션의 헬스 체크와 메트릭 데이터를 노출하고, Prometheus는 이 메트릭을 주기적으로 수집·저장하는 모니터링 서버 역할을 하며, Grafana는 Prometheus에 저장된 데이터를 기반으로 시각화 대시보드를 제공해 실시간 상태를 모니터링할 수 있다.