// 관심 상품 등록하기
@PostMapping("/products")
public ProductResponseDto createProduct(
@RequestBody ProductRequestDto requestDto,
@AuthenticationPrincipal UserDetailsImpl userDetails) {
// 측정 시작 시간
long startTime = System.currentTimeMillis();
try {
// 응답 보내기
return productService.createProduct(requestDto, userDetails.getUser());
} finally {
// 측정 종료 시간
long endTime = System.currentTimeMillis();
// 수행시간 = 종료 시간 - 시작 시간
long runTime = endTime - startTime;
// 로그인 회원 정보
User loginUser = userDetails.getUser();
// API 사용시간 및 DB 에 기록
ApiUseTime apiUseTime = apiUseTimeRepository.findByUser(loginUser).orElse(null);
if (apiUseTime == null) {
// 로그인 회원의 기록이 없으면
apiUseTime = new ApiUseTime(loginUser, runTime);
} else {
// 로그인 회원의 기록이 이미 있으면
apiUseTime.addUseTime(runTime);
}
System.out.println(
"[API Use Time] Username: "
+ loginUser.getUsername()
+ ", Total Time: "
+ apiUseTime.getTotalTime()
+ " ms");
apiUseTimeRepository.save(apiUseTime);
}
}
핵심기능에 전부 필요하다면? 혹은 핵심기능이 지속적으로 추가가된다면? 아니면 코드를 추가하는 것을 까먹는다면?


@Aspect
어드바이스 : 부가기능이 핵심기능의 언제 수행할지 정함.
포인트 컷 : 언제 뿐만 아니라 어디에 수행할지도 지정 지역적

하지만 모든 부가기능에서 하나하나 포인트컷을 어드바이스에 적용하게된다면 생산성 면에서 너무 효율이 떨어진다.
이를 대비하기 위하여 @Pointcut 을 제공한다.
@Component
@Aspect
public class Aspect {
@Pointcut("execution(* com.sparta.myselectshop.controller.*.*(..))")
private void forAllController() {}
@Pointcut("execution(String com.sparta.myselectshop.controller.*.*())")
private void forAllViewController() {}
@Around("forAllContorller() && !forAllViewController()")
public void saveRestApiLog() {
...
}
@Around("forAllContorller()")
public void saveAllApiLog() {
...
}
}
@Pointcut("execution(* com.sparta.myselectshop.controller.*.*(..))") private void forAllController() {} 위 와같이 포인트컷의 지정을 메소드명으로 지정이 가능하다.
@Around("forAllContorller()") public void saveAllApiLog() { ... } 어드바이스 내부에선 메소드명으로 포인트컷 지정이 가능!


@Slf4j(topic = "UseTimeAop")
@Aspect
@Component
@RequiredArgsConstructor
public class UseTimeAop {
private final ApiUseTimeRepository apiUseTimeRepository;
@Pointcut("execution(* com.sparta.myselectshop.controller.ProductController.*(..))")
private void product() {}
@Pointcut("execution(* com.sparta.myselectshop.controller.FolderController.*(..))")
private void folder() {}
@Pointcut("execution(* com.sparta.myselectshop.naver.controller.NaverApiController.*(..))")
private void naver() {}
@Around("product() || folder() || naver()")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
// 측정 시작 시간
long startTime = System.currentTimeMillis();
try {
// 핵심기능 수행
Object output = joinPoint.proceed();
return output;
} finally {
// 측정 종료 시간
long endTime = System.currentTimeMillis();
// 수행시간 = 종료 시간 - 시작 시간
long runTime = endTime - startTime;
// 로그인 회원이 없는 경우, 수행시간 기록하지 않음
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null && auth.getPrincipal().getClass() == UserDetailsImpl.class) {
// 로그인 회원 정보
UserDetailsImpl userDetails = (UserDetailsImpl) auth.getPrincipal();
User loginUser = userDetails.getUser();
// API 사용시간 및 DB 에 기록
ApiUseTime apiUseTime = apiUseTimeRepository.findByUser(loginUser).orElse(null);
if (apiUseTime == null) {
// 로그인 회원의 기록이 없으면
apiUseTime = new ApiUseTime(loginUser, runTime);
} else {
// 로그인 회원의 기록이 이미 있으면
apiUseTime.addUseTime(runTime);
}
log.info(
"[API Use Time] Username: "
+ loginUser.getUsername()
+ ", Total Time: "
+ apiUseTime.getTotalTime()
+ " ms");
apiUseTimeRepository.save(apiUseTime);
}
}
}
}