AOP๋ž€?

Aspect Oriented Programming์˜ ์•ฝ์ž๋กœ ๊ด€์  ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด๋‹ค

๋กœ์ง์„ ํ•ต์‹ฌ ๊ธฐ๋Šฅ๊ณผ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์˜ ๊ด€์ ์œผ๋กœ ๋‚˜๋ˆ„์–ด์„œ ๋ณด๊ณ  ๊ฐ๊ฐ์„ ๋ชจ๋“ˆํ™” ํ•˜๋Š”๊ฒƒ์ด AOP์˜ ํ•ต์‹ฌ์ด๋‹ค

์‡ผํ•‘๋ชฐ๋กœ ์˜ˆ๋ฅผ ๋“ค๋ฉด ์ƒํ’ˆ์„ ๊ฒ€์ƒ‰ํ•˜๊ณ , ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ๋‹ด๊ณ , ๊ฒฐ์ œํ•˜๋Š” ๋ถ€๋ถ„์€ ํ•ต์‹ฌ์ ์ธ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ๊ณ , ์œ ์ €๋ณ„๋กœ ํ™ˆํŽ˜์ด์ง€์— ์ฒด๋ฅ˜ํ•˜๋Š” ์‹œ๊ฐ„์„ ์ธก์ •ํ•˜๋Š” ๋ถ€๋ถ„์€ ๋ถ€๊ฐ€ ๊ธฐ๋Šฅ์— ํ•ด๋‹นํ•œ๋‹ค.

AOP๋Š” ๋ถ€๊ฐ€๊ธฐ๋Šฅ์„ Aspect๋กœ ์ •์˜ํ•˜์—ฌ ํ•ต์‹ฌ ๊ธฐ๋Šฅ์—์„œ ๋ถ€๊ฐ€๊ธฐ๋Šฅ์„ ๋ถ„๋ฆฌํ•œ๋‹ค.

AOP ์ฃผ์š” ๊ฐœ๋…

  • Join point : Aspect๊ฐ€ ์ ์šฉ๋  ์ˆ˜ ์žˆ๋Š” ์‹œ์ 

    • @Around : ํ•ต์‹ฌ๊ธฐ๋Šฅ ์ˆ˜ํ–‰ ์ „๊ณผ ํ›„์— ์–ด๋“œ๋ฐ”์ด์Šค ๊ธฐ๋Šฅ ์ˆ˜ํ–‰
    • @Before : ํ•ต์‹ฌ๊ธฐ๋Šฅ ํ˜ธ์ถœ ์ „์— ์ˆ˜ํ–‰
    • @After : ํ•ต์‹ฌ๊ธฐ๋Šฅ ์ˆ˜ํ–‰ ์„ฑ๊ณต/์‹คํŒจ ์—ฌ๋ถ€์™€ ์ƒ๊ด€์—†์ด ์–ธ์ œ๋‚˜ ๋™์ž‘
    • @AfterReturning : ํ•ต์‹ฌ๊ธฐ๋Šฅ ํ˜ธ์ถœ ์„ฑ๊ณต ์‹œ ์ˆ˜ํ–‰
    • @AfterThrowing : ํ•ต์‹ฌ๊ธฐ๋Šฅ ํ˜ธ์ถœ ์‹คํŒจ ์‹œ ์ˆ˜ํ–‰
  • Advice : Aspect์˜ ๊ธฐ๋Šฅ์„ ์ •์˜ํ•œ ๊ฒƒ

  • Point cut : Advice๋ฅผ ์ ์šฉํ•  ๋ฉ”์†Œ๋“œ ๋ฒ”์œ„ ์ง€์ •

@Slf4j(topic = "UseTimeAop")
@Aspect
@Component
@RequiredArgsConstructor
public class UserTimeAop {
    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();
 
                ApiUseTime apiUseTime = apiUseTimeRepository.findByUser(loginUser).orElse(null);
 
                if(apiUseTime == null) {
                    apiUseTime = new ApiUseTime(loginUser, runTime);
                } else {
                    apiUseTime.addUseTime(runTime);
                }
 
                apiUseTimeRepository.save(apiUseTime);
            }
 
        }
    }
 
}

Spring์—์„œ์˜ AOP

์Šคํ”„๋ง AOP๋Š” ํ”„๋ก์‹œ ๊ธฐ๋ฐ˜์˜ AOP ๊ตฌํ˜„์ฒด์ด๋‹ค.

์Šคํ”„๋ง์ด ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์ค‘๊ฐ„์— ์‚ฝ์ž…ํ•˜์—ฌ ๋™์ž‘ํ•˜๋Š” ํ˜•ํƒœ์ด๋‹ค.