코딩하는 문과생

[Spring Boot] Spring AOP, 예외 처리 본문

웹 프로그래밍/Spring Boot

[Spring Boot] Spring AOP, 예외 처리

코딩하는 문과생 2023. 12. 20. 17:10

프로젝트 투입 전 약간의 시간이 있어, 스프링을 전체적으로 정리중에 있다. 

 

그중 스프링 검증과 예외처리에 대해 한번의 정리가 필요한 것 같아 그 내용을 정리해보려고 한다.

원론적인 이야기는 배제하고, 실무적으로 필요한 것만 정리한 내용이다.


 

[Spring AOP]

Spring은 공통 관심사와 비즈니스 로직을 분리할 수 있도록 AOP기능을 제공한다.

즉, 비즈니스 로직에 모든 것을 담으려하지 않고, 예외처리나 로깅 등은 공통 관심사로 뽑아내어 로직을 만들어 핵심 비즈니스 변경 시 영향도를 최대한 줄이고자 한다.

 

[포인트 컷과 어드바이스]

 

조인 포인트(Join point) Advice가 적용될 수 있는 위치.
AOP를 적용할 수 있는 모든 지점.
스프링 AOP는 프록시 방식을 사용하기 때문에 조인 포인트는 항상 메서드 실행지점으로 제한된다.
포인트컷(Pointcut) 조인 포인트 중에서 Advice가 적용될 위치를 선별
주로 AspectJ 표현식을 사용해서 지정
어드바이스(Advice) 부가기능
조인 포인트에서 취해지는 조치사항

 

즉 포인트 컷은 위치를 선별, 어드바이스는 부가기능이라 생각하면 된다.

포인트컷과 어드바이스를 직접 자바로 구현하는 방법이 있긴 하지만, 스프링 부트에서는 위 과정을 어노테이션 등으로 쉽게 처리하는 방법을 제공해준다.

 

[실무적인 예외처리 기법]

예전의 스프링은 예외처리에 대해 일일이 구현을 해야했다면, Spring AOP와 Spring Boot 자동환경설정 등으로 간략히 예외처리를 구성할 수 있다.

 

전제)

Rest API 서버에서 예외발생 시 일관된 예외 리턴

 

방법 CASE)

1. ControllerAdvice + 자바 정의 예외

2. ControllerAdvice + 사용자 정의 예외

3. ResponseEntityExceptionHandler 클래스의 메서드를 오버라이드하여 정의하는 예외

 

예외처리 패키지 구성

 

 

. CustomizedResponseEntityExceptionHandler.java

package kr.co.sijune.myrestfulservice.exception;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import java.util.Date;

@ControllerAdvice
public class CustomizedResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {

    /* CASE 1 : ControllerAdvice + 자바 정의 예외 */
    @ExceptionHandler(Exception.class)
    public final ResponseEntity<Object> handleAllException(Exception ex, WebRequest request) {

        ExceptionResponse exceptionResponse = new ExceptionResponse(new Date(), ex.getMessage(), request.getDescription(false));
        return new ResponseEntity<>(exceptionResponse, HttpStatus.INTERNAL_SERVER_ERROR);
    }

    /* CASE 2 : ControllerAdvice + 사용자 정의 예외 */
    @ExceptionHandler(UserNotFoundException.class)
    public final ResponseEntity<Object> handleUserNotFoundException(Exception ex, WebRequest request) {

        ExceptionResponse exceptionResponse = new ExceptionResponse(new Date(), ex.getMessage(), request.getDescription(false));
        return new ResponseEntity<>(exceptionResponse, HttpStatus.NOT_FOUND);
    }

    /* CASE 3 : ResponseEntityExceptionHandler 클래스의 메서드를 오버라이드하여 정의하는 예외 */
    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) {
        ExceptionResponse exceptionResponse = new ExceptionResponse(new Date(), ex.getMessage(), ex.getBindingResult().toString());
        return new ResponseEntity<>(exceptionResponse, HttpStatus.BAD_REQUEST);
    }
}

 

 

. ExceptionResponse.java

package kr.co.sijune.myrestfulservice.exception;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ExceptionResponse {
    private Date timestamp;
    private String message;
    private String details;
}

 

 

. UserNotFoundException.java

package kr.co.sijune.myrestfulservice.exception;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(HttpStatus.NOT_FOUND)
public class UserNotFoundException extends RuntimeException{
    public UserNotFoundException(String message) {
        super(message);
    }
}

 

 

예외처리 결과


https://backtony.github.io/spring/2021-12-29-spring-aop-2/

 

Spring - AOP 총정리

Java, JPA, Spring을 주로 다루고 공유합니다.

backtony.github.io