본문 바로가기
Software Tech/Spring (feat.JAVA)

[AOP] Aspect & Logging (feat. SpringBoot)

by SuperDev 2025. 5. 12.

아래 코드를 통해 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