1. AOP
- Aspect Oriented Programming, 관점 지향 프로그래밍
- 공통 관심 사항 / 핵심 관심 사항을 분리시킴
2. Spring AOP
- 스프링에서 제공하는 AOP 구현체
- 공통 관심 사항을 모듈화(: 공통 로직, 기능 등을 하나의 단위로 묶는 것) 하여 관리할 수 있는 편의 기능 제공
- 핵심 기능 : 코드 수정 없이 공통 기능을 추가하는 것!
- 프록시 객체를 자동 생성함
- 프록시 : 대리자라는 뜻
- 클라이언트가 접근하는 실제 객체 (타겟 객체) 인 것처럼 위장 → 요청을 대신 받아줌
- 또한 받은 요청을 바로 타겟 객체에게 넘겨주기 전 다양한 로직 추가 가능
⇒ AOP 적용 후 : 프록시 객체가 (Dispatcher Servlet → 컨트롤러) 요청을 가로챔
- 스프링 AOP 동작 흐름
AOP : Dispatcher Servlet과 컨트롤러 사이에서 수행됨!
2-1. 주요 개념 및 용어
- Target : Aspect가 적용되는 비즈니스 로직을 가진 객체 ⇒ “advice (부가 기능)을 추가할 대상”
- Advice : 부가 기능 혹은 공통 기능 / joinpoint 에서 실행되는 코드
- @Before : target의 메서드 호출 전에 공통 기능 실행
- @After : target의 메서드 호출 후에 공통 기능 실행
- @Around : target의 메서드 호출 전, 후, 예외 발생 시 공통 기능 실행
- @AfterReturning : 값을 반환한 후에 공통 기능 실행
- @AfterThrowing : 예외가 발생한 경우 공통 기능 실행
- 동작 순서 : @Around > @Before > @AfterThrowing > @After > @AfterReturning > @Around
- Weaving : advice를 핵심 기능 코드에 적용하는 것
- 컴파일 시 위빙, 런타임 시 위빙 존재 ⇒ 스프링 AOP는 런타임 시 위빙!
- Join Point : advice가 적용될 수 있는 위치
⇒ 스프링 AOP : 프록시 방식 사용하므로 join point는 항상 “메소드 호출” 지점에 대해서만 제공됨 - Pointcut : join point 중 advice를 어떤 대상에게 적용할 지 지정하는 방법
- 주로 AspectJ 표현식 사용
📌 execution 명시자
- AspectJ에서 사용되는 pointcut 표현식의 한 종류
execution( [접근 제어자] 반환타입 [패키지/클래스.] 메서드명 (매개변수타입 | “..”, ...) [throw 예외] )
- 예시
1. 패키지 내의 모든 클래스의 모든 메서드 : execution(* com.example.service.*.*(..))
2. 클래스 내의 반환 타입이 String인 모든 메서드 : execution(String com.example.service.MyService.*(..))
3. MyService 클래스의 add 메서드 : execution(* com.example.service.MyService.add(..))
4. com.example.service 패키지 내 모든 클래스에서 String 타입 매개변수 받는 delete 메서드 : execution(* com.example.service.*.delete(String))
- Aspect : advice + pointcut 조합으로 구성됨 / 공통 관심 사항에 대한 특정 기능을 지칭
3. 스프링 AOP 활용한 예외 처리
- 예외 (종류, 처리방법)
2024.07.28 - [Java] - [Java] 예외 처리 (Exception Handling)
📌 throws vs try-catch
- throws : 메서드 선언부에 사용 ⇒ 메서드를 호출하는 쪽에서 예외 처리하도록 함!
- try-catch : 메서드 실행 코드 블록 내에 위치 ⇒ 코드 내에서 발생할 수 있는 예외를 직접 처리
- 스프링 AOP 사용 예외 처리
- 주로 공통 예외의 처리를 중앙 집중화함 ⇒ 코드 중복 줄임, 관심사 분리!
- AOP 통해 특정 메서드에서 발생하는 예외를 가로채고 공통적인 예외 처리 로직 적용
- 예외 처리 영역에 따른 예외 처리 방법 2가지
- @ExceptionHandler 사용 : 클래스 영역의 예외 처리
- @ControllerAdvice 사용: 전범위 영역의 예외 처리
3-1. @ExceptionHandler 사용한 예외 처리
- 특정 클래스(컨트롤러) 내에서 발생하는 예외를 처리하는 메서드 정의
- @ExceptionHandler(처리할 에러클래스) 어노테이션을 붙인 에러 처리 메서드 정의
3-1-1. 예제 코드
- 컨트롤러
@RestController
@Slf4j
public class ExceptionController {
@GetMapping("/exception")
public String exception() {
// 예외 발생 코드
throw new RuntimeException("예외 발생함");
}
@ExceptionHandler(RuntimeException.class)
public ResponseEntity<String> handleRuntimeException(RuntimeException ex) {
log.error("런타임 예외 발생");
return new ResponseEntity<>("처리된 예외: " + ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
3-2. @(Rest)ControllerAdvice 사용한 예외 처리
- 모든 컨트롤러에 대해 전역적으로 예외 처리 가능한 방법
- 모든 컨트롤러에서 발생하는 예외를 중앙 처리 가능!
- @(Rest)ControllerAdvice 어노테이션을 붙인 예외 처리 클래스 선언
→ 클래스 내부에 @ExceptionHandler 예외 처리 메서드 선언
📌 @ControllerAdvice vs @RestControllerAdvice
- @ControllerAdvice → @Controller 에만 적용되고
@RestControllerAdvice → @RestController 에만 적용되는 것이 아님!
- @Controller, @RestController 와 같이 @ControllerAdvice + @ResponseBody = @RestControllerAdvice 임
- @RestControllerAdvice 적용 범위 설정
- @RestControllerAdvice (annotations = Controller.class) 와 같이 특정 어노테이션만 적용
- @RestControllerAdvice (basePackages = 패키지경로) 와 같이 특정 패키지에만 적용
3-2-1. 예제 코드
@Slf4j
@RestControllerAdvice
public class MyExceptionHandler {
@ExceptionHandler(MyException.class)
public ErrorResponse handleMyException(MyException ex) {
log.error("사용자 정의 예외 발생");
return new ErrorResponse("사용자 정의 예외", ex.getMessage());
}
@ExceptionHandler(RuntimeException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ErrorResponse handleRuntimeException(RuntimeException ex) {
log.error("런타임 예외 발생");
return new ErrorResponse("런타임 예외", ex.getMessage());
}
}
3-3. @Aspect 사용한 예외 처리
- 전역적으로 예외 처리 공통화!
3-3-1. 예제 코드
@Aspect
@Component
@Slf4j
public class MyLoggingAspect {
@Pointcut("execution(* com.example.service.MyService.*(..))")
public void pointcutMethods() {}
@AfterThrowing(pointcut = "pointcutMethods()", throwing="ex")
public void mylogger(MyException ex) {
log.error("예외가 발생함");
log.error("메서드: {}, 에러 메시지: {}", ex.getStackTrace()[0].getMethodName(), ex.getMessage());
}
}
- @Pointcut 통해서 예외 처리를 공통화 할 pointcut 지정 (MyService 클래스의 모든 메서드)
- @AfterThrowing 통해서 MyException 예외 발생 시 mylogger() 메서드가 실행됨 → 로그 출력
'Spring Boot' 카테고리의 다른 글
[Spring Boot] MapStruct 라이브러리로 엔티티 ↔ DTO 변환 자동으로 매핑하기 (예제 코드) (0) | 2024.08.14 |
---|---|
[Spring Boot] 데이터 바인딩 예제 (@RequestParam, @ModelAttribute, @RequestBody) (0) | 2024.08.14 |
[Spring Boot] 스프링 유효성 검사 Validation (@Valid, @Validated, Bean Validation) (0) | 2024.08.13 |
[Thymeleaf] Thymeleaf 기본 문법 (+ 적용 방법) (0) | 2024.08.11 |
[Spring Boot] 프로젝트에 Swagger 적용, Swagger 어노테이션 정리 (0) | 2024.05.11 |