
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을 사용해서 해당 객체가 프록시를 적용할 대상인지 아닌지 확인공부한 내용으로 틀린 정보가 있을 수 있습니다.