AOP는 Aspect Oriented Programming 의 약자로 관점 지향 프로그래밍이라고 한다.

OOP를 설계 할 때 각각의 함수 또는 모듈마다 트랜잭션, 보안, 시간재기, 로깅과 같은 것을 다 써놓았는데 이것들을 모듈화 시키는 개념이다.

🔍 RunningTIME

@Target(ElementType.METHOD)
public @interface RunningTime {
}

위 코드처럼 어노테이션을 만들 수 있다.

🔍 DebuggingAspect

@Aspect
@Component
@Slf4j
public class DebuggingAspect {

    @Pointcut("@annotation(com.example.shoppingmall.aop.annotation.RunningTime)")
    private void enableRunningTime(){}

    @Pointcut("execution(* com.example.shoppingmall.api.*.*(..))")
    private void controllerPointcut(){}

    @Around("enableRunningTime()")
    public Object loggingRunningTime(ProceedingJoinPoint joinPoint) throws Throwable{
        StopWatch stopWatch = new StopWatch();

        stopWatch.start();
        Object returningObh = joinPoint.proceed();
        stopWatch.stop();

        String methodName = joinPoint.getSignature().getName();

				log.info("'{}' total running time : {} sec", methodName, stopWatch.getTotalTimeSeconds());

        return returningObh;
    }

    @Around("controllerPointcut()")
    public Object loggingRunningTimeController(ProceedingJoinPoint joinPoint) throws Throwable{
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();

        StopWatch stopWatch = new StopWatch();
        Map<String, Object> params = new HashMap<>();

        stopWatch.start();
        Object returningObh = joinPoint.proceed();
        stopWatch.stop();

        String methodName = joinPoint.getSignature().getName();
        try {
            params.put("method", joinPoint.getSignature().getName());
            params.put("logTime", LocalDateTime.now().withNano(0));
            params.put("requestURI", request.getRequestURI());
            params.put("http_method", request.getMethod());
        } catch (Exception e) {
						log.error("LoggerAspect error", e);
        }
						log.info("{}", params);
						log.info("'{}' total running time : {} sec\\n\\n", methodName, stopWatch.getTotalTimeSeconds());

        return returningObh;
    }
}

위의 코드처럼 어려운건 없지만 주의할 점은 있다.

AOP 기능을 원하는 메서드가 Return Object가 존재한다면 해당 AOP 메서드에서도 꼭 return returningObh 와 같이 return 해주어야한다.