AOP를 처음 접할때 Logging
과 더불어 가장 많이 쓰이는 예제인 메서드 실행시간 측정
기능을 구현해볼께요.
AOP
의 적용 지점은 패키지, 클래스, 메서드 등 여러 방식으로 지정 가능합니다.
이번에는 어노테이션을 기반으로 적용지점을 설정해볼께요.
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ExeTimer {
}
위에 작성한 어노테이션 @ExeTimer
가 붙은 메서드에 대해 AOP가 수행되도록 할 것입니다.
@PointCut
을 통해 모든 JointPoint
에서 적용될 JoinPoint
를 지정합니다.
@annotation
을 이용해서 작성한 어노테이션의 path를 지정합니다.
메서드 실행 전, 후로 실행시간을 측정하고자 합니다.
Spring AOP
는 @Before
, @AfterReturning
등 메서드 전,후로 호출되는 메서드를 지원하는데 실행시간을 측정할 때에는 한 개 변수를 실행시간 전,후로 공유해야 하기 때문에 @Around
를 사용합니다.
Stopwatch
클래스를 이용해서 시간을 측정했고 메서드 이름과 함께 로그가 찍히도록 설정했습니다.
@Slf4j
@Aspect
@Component
public class ExecutionTimer {
// 조인포인트를 어노테이션으로 설정
@Pointcut("@annotation(com.aop.annotation.ExeTimer)")
private void timer(){};
// 메서드 실행 전,후로 시간을 공유해야 하기 때문
@Around("timer()")
public void AssumeExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
joinPoint.proceed(); // 조인포인트의 메서드 실행
stopWatch.stop();
long totalTimeMillis = stopWatch.getTotalTimeMillis();
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
String methodName = signature.getMethod().getName();
log.info("실행 메서드: {}, 실행시간 = {}ms", methodName, totalTimeMillis);
}
}
매핑된 컨트롤러의 메서드로 요청이 왔을 때 해당 메서드의 실행시간을 측정하고자 합니다.
실행시간을 측정하는 많은 경우가 있는데 보편적으로 프로젝트의 큰 병목지점이 되는 DB 엑세스 부분이 많을 것 입니다.
/db-access
로 요청이 왔을 때 DB에 접근한다고 가정하고 임의로 1초의 sleep
을 주었습니다.
그리고 작성한 실행시간 측정 AOP
를 적용시키기 위해 @ExeTimer
를 추가합니다.
@ExeTimer
@GetMapping("/db-access")
public String dbAccess() throws InterruptedException {
Thread.sleep(1000); // DB 접근시 1초가 걸린다고 가정
return "db";
}
실행시간 측정 결과
잘 되었네요 ㅎ
감사합니다. 😁