아래 코드를 통해 AOP와 Logging에 대해 이해해봅시다.
해당 코드는 Spring AOP를 활용하여 서비스와 컨트롤러 계층의 메서드 실행 전에 로그를 출력하는 기능을 수행합니다.
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Aspect
@Component
@Slf4j
public class LoggingAspect {
@Pointcut("excution(* earthlab.blog_ai.service.*.*(..))")
private void serviceMethods() {}
@Pointcut("excution(* earthlab.blog_ai.controller.*.*(..))")
private void controllerMethods() {}
@Before("serviceMethods() || controllerMethods()")
public void logBefore(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().toShortString();
log.info("시작: {}, 매개변수: {}", methodName, Arrays.toString(joinPoint.getArgs()));
}
@AfterReturning(pointcut = "serviceMethods() || controllerMethods()", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
String methodName = joinPoint.getSignature().toShortString();
log.info("종료: {}, 반환값: {}", methodName, result);
}
@AfterThrowing(pointcut = "serviceMethods() || controllerMethods()", throwing = "exception")
public void logAfterThrowing(JoinPoint joinPoint, Exception exception) {
String methodName = joinPoint.getSignature().toShortString();
log.error("예외 발생: {}, 예외 타입: {}, 메시지: {}", methodName, exception.getClass().getName(), exception.getMessage());
}
@Around("serviceMethods() || controllerMethods()")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = joinPoint.proceed();
long endTime = System.currentTimeMillis();
String methodName = joinPoint.getSignature().toShortString();
log.info("수행시간: {}, 소요시간: {}ms", methodName, (endTime - startTime));
return result;
}
}
1. Import
- Aspect : 이 클래스가 AOP의 핵심 로직을 담고 있다는 의미 입니다.
- Component : Spring Bean으로 등록되게 해줍니다.
- JoinPoint : Advice가 적용되는 메서드의 정보를 담고 있는 객체 입니다.
- Arrays.toString() : 배열을 문자열로 보기 좋게 출력하기 위한 것.
2. 클래스 선언부
- @Aspect : 해당 클래스가 관점(Aspect)임을 나타냅니다.
- @Component : 이 클래스를 Spring이 자동으로 Bean으로 등록하게 합니다.
- @Slf4j : 로그를 사용할 수 있도록 log 객체를 자동 생성합니다.
3. Pointcut
@Pointcut("excution(* earthlab.blog_ai.service.*.*(..))")
private void serviceMethods() {}
@Pointcut("execution(* earthlab.blog_ai.controller.*.*(..))")
private void controllerMethods() {}
- service 패키지 아래의 모든 메서드 실행 지점을 포인트컷으로 지정합니다.
- controller 패키지의 모든 메서드 실행 지점도 포인트컷으로 설정합니다.
4. @Before 어드바이스
@Before("serviceMethods() || controllerMethods()")
public void logBefore(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().toShortString();
log.info("시작: {}, 매개변수: {}", methodName, Arrays.toString(joinPoint.getArgs()));
}
- @Before : 지정된 포인트컷의 메서드 실행 전에 이 메서드를 실행합니다.
- joinPoint : 현재 호출된 메서드에 대한 정보 제공
- joinPoint.getSignature().toShortString() -> 어떤 메서드인지 이름만 간단히 출력
- joinPoint.getArgs() -> 전달된 매개변수들을 배열로 가져옵니다.
5. @AfterReturning - 정상 종료 후 반환값 로깅
@AfterReturning(pointcut = "serviceMethods() || controllerMethods()", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
String methodName = joinPoint.getSignature().toShortString();
log.info("종료: {}, 반환값: {}", methodName, result);
}
- joinPoint 메서드가 정상적으로 반환 되었을 때 실행됩니다.
- returning = "result"는 반환값을 받아서 로그에 출력하기 위한 것 입니다.
- 메서드가 종료되면 로그가 찍힙니다.
6. @AfterThrowing - 예외 발생 시 로깅
@AfterThrowing(pointcut = "serviceMethods() || controllerMethods()", throwing = "exception")
public void logAfterThrowing(JoinPoint joinPoint, Exception exception) {
String methodName = joinPoint.getSignature().toShortString();
log.error("예외 발생: {}, 예외 타입: {}, 메시지: {}", methodName, exception.getClass().getName(), exception.getMessage());
}
- 메서드 실행 중 예외가 발생하면 실행됩니다.
- throwing = "exception"은 예외 객체를 받아오기 위한 설정 입니다.
- log.error를 사용하여 예외 로그를 기록합니다.
7. @Around - 실행 시간 측정
@Around("serviceMethods() || controllerMethods()")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = joinPoint.proceed(); // 실제 메서드 실행
long endTime = System.currentTimeMillis();
String methodName = joinPoint.getSignature().toShortString();
log.info("수행시간: {}, 소요시간: {}ms", methodName, (endTime - startTime));
return result;
}
- @Around는 메서드 실행 전후 전체를 감싸며 실행 시간 등을 측정할 때 사용합니다.
- proceed()로 실제 메서드를 실행하고, 전후 시간 차를 계산하여 소요 시간을 기록합니다.
728x90
'Software Tech > Spring (feat.JAVA)' 카테고리의 다른 글
[클린코드] 2. 주석 & 형식 맞추기 & 객체와 자료구조 (1) | 2025.05.17 |
---|---|
[클린코드] 1. 깨끗한 코드와 함수 (1) | 2025.05.15 |
[Java] Spring 시작하기 (0) | 2025.01.07 |
Servlet & JSP에 대하여 (1) | 2024.12.26 |
MVC 패턴 (Model-View-Controller) (2) | 2024.11.19 |