AOP를 활용하여 메서드의 실행 시간을 측정하기
Spring Boot: 3.1.0
실행 시간을 측정하고 싶은 메서드에 @TimeTrace
라는 어노테이션을 추가하면 동작되도록하자.
implementation("org.springframework.boot:spring-boot-starter-aop")
spring-boot-starter-aop
가 필요하다. 없으면 추가하자.
package com.example.demo.config.aop;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TimeTrace {
}
package com.example.demo.config.aop;
import lombok.extern.log4j.Log4j2;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
@Log4j2
@Component
@Aspect
public class TimeTraceAspect {
// @Pointcut("execution(* com.example.demo.repository..*(..))")
@Pointcut("@annotation(com.example.demo.config.aop.TimeTrace)")
private void timeTracePointcut() {
}
@Around("timeTracePointcut()")
public Object traceTime(ProceedingJoinPoint joinPoint) throws Throwable {
StopWatch stopWatch = new StopWatch();
try {
stopWatch.start();
return joinPoint.proceed(); // 실제 타겟 호출
} finally {
stopWatch.stop();
log.debug("{} - Total time = {}s",
joinPoint.getSignature().toShortString(),
stopWatch.getTotalTimeSeconds());
}
}
}
PCD(Pointcut Designator)
는 @annotaion
을 사용TimeTrace
어노테이션을 가지고 있는 메서드를 타겟으로 함Advice
는 실제 타겟 호출 전, 후에 로직이 있으므로 @Around
를 사용StopWatch
를 시작, 마지막에 StopWatch
를 종료하고 로그를 남기는 로직// controller
@RestController
@RequiredArgsConstructor
public class HelloController {
private final HelloService helloService;
@TimeTrace
@GetMapping("hello")
public void hello() throws InterruptedException {
helloService.hello();
}
}
// service
@Service
public class HelloServiceImpl implements HelloService {
@TimeTrace
@Override
public void hello() throws InterruptedException {
Thread.sleep(1000);
}
}
... HelloServiceImpl.hello() - Total time = 1.005074833s
... HelloController.hello() - Total time = 1.009257125s
메서드에 @TimeTrace
어노테이션만 추가 했을 뿐인데 어떻게 프록시를 적용할 수 있었을까?
Spring Boot는 Auto-Configuration
기능이 있다.
// ...
@EnableAutoConfiguration
// ...
public @interface SpringBootApplication {
@SpringBootApplication
어노테이션을 보면 @EnableAutoConfiguration
이 포함되어 있다.우리가 라이브러리를 사용할 때, 사용자 입장에서는 어떤 객체들을 스프링 빈으로 등록해야 하는지 모른다. 사용자들이 사용할 라이브러리의 스프링 빈을 직접 등록해서 사용해야한다면 번거로울 것이다.
자동 구성이 적용된 라이브러리는 추가만하면 스프링 빈들이 자동으로 등록된다. 예를 들면 우리가 Spring Data JPA를 사용할 때 DataSource
, TransationManager
같은 빈들을 따로 등록하지 않아도 자동으로 등록된다.
마찬가지로 spring-boot-starter-aop
를 추가하면 AnnotationAwareAspectJAutoProxyCreator
라는 빈 후처리기가 자동으로 스프링 빈에 등록된다.
빈 후처리기는 객체를 스프링 빈에 등록하기 직전 조작을 할 수 있게 한다.
@Aspect
어노테이션이 있는 스프링 빈을 BeanFactoryAspectJAdvisorBuilder
를 통해 Advisor
를 생성하고 저장함Advisor
의 정보를 기반으로 적용 대상을 확인하고 프록시를 생성함AnnotationAwareAspectJAutoProxyCreator
(빈 후처리기)에 전달됨AnnotationAwareAspectJAutoProxyCreator
로직Advisor
생성@Aspect
어노테이션이 있는 스프링 빈을 BeanFactoryAspectJAdvisorBuilder
를 통해 Advisor
를 생성하고 저장함Advisor
조회Advisor
빈 조회BeanFactoryAspectJAdvisorBuilder
에 저장된 Advisor
조회Advisor
의 Pointcut
을 사용해서 해당 객체가 프록시를 적용할 대상인지 아닌지 확인공부한 내용으로 틀린 정보가 있을 수 있습니다.