Spring๐Ÿƒ

Spring AOP

wannaDevelopIt 2022. 12. 28. 12:02
728x90

์ถœ์ฒ˜ : ๋‚ด์ผ๋ฐฐ์›€์บ ํ”„

 

Aspect Oriented Programming : ๊ด€์ ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ

  1. AOP ๊ฐœ๋… ์ดํ•ด
  2. '๋‚˜๋งŒ์˜ ์…€๋ ‰์ƒต' ์— ์Šคํ”„๋ง AOP ์ ์šฉ
    1. Top5 ํšŒ์› ์ฐพ๊ธฐ
    2. ์ค‘๋ณต ํด๋”๋ช… ์ €์žฅ ์‹œ ์—๋Ÿฌ ์ฒ˜๋ฆฌ
    3. ์Šคํ”„๋ง ์˜ˆ์™ธ ์ฒ˜๋ฆฌ

์„œ๋ฒ„๋ฅผ ์‚ฌ์šฉํ•œ ์‹œ๊ฐ„ ~ ๋ชจ๋“  API์— ์š”์ฒญ, ์‘๋‹ตํ•œ ์‹œ๊ฐ„์˜ ํ•ฉ์„ ๊ธฐ์ค€์œผ๋กœ ์ƒ์œ„ 5์ธ ์„ ๋ฐœ

์Šคํฌ๋ž˜์น˜ ํŒŒ์ผ์„ ์ด์šฉํ•œ ์„œ๋ฒ„ ์‚ฌ์šฉ์‹œ๊ฐ„ ์ธก์ •

+ ์Šคํฌ๋ž˜์น˜ ํŒŒ์ผ์€ ๋ณ„๋„๋กœ ์ €์žฅ๋˜๋Š” ์ž„์‹œํŒŒ์ผ, ํ”„๋กœ์ ํŠธ์™€ ๊ด€๋ จ์—†๋Š” ์ฝ”๋“œ๋ฅผ ๋‹ค๋ฃฐ ๋•Œ ์œ ์šฉํ•˜๋‹ค

์Šคํฌ๋ž˜์น˜ ํŒŒ์ผ ๊ฒฝ๋กœ

class Scratch {
    public static void main(String[] args) {
        // ์ธก์ • ์‹œ์ž‘ ์‹œ๊ฐ„
        long startTime = System.currentTimeMillis();

        // ํ•จ์ˆ˜ ์ˆ˜ํ–‰
        long output = sumFromOneTo(1_000_000_000);

        // ์ธก์ • ์ข…๋ฃŒ ์‹œ๊ฐ„
        long endTime = System.currentTimeMillis();

        long runTime = endTime - startTime;
        System.out.println("์†Œ์š”์‹œ๊ฐ„: " + runTime);
    }

    private static long sumFromOneTo(long input) {
        long output = 0;

        for (int i = 1; i < input; ++i) {
            output = output + i;
        }

        return output;
    }
}

output์˜ ๊ฐ’์„ ์ดˆ๊ธฐ๊ฐ’ 1์ดˆ๋กœ ์„ค์ •ํ•œ ํ›„, ์‚ฌ์šฉ์‹œ๊ฐ„๋งŒํผ ๊ฐ’์„ ์ฆ๊ฐ€์‹œํ‚ค๋Š” ๋ฐ˜๋ณต๋ฌธ์„ ํ†ตํ•ด ์‹œ๊ฐ„์˜ ํ•ฉ์„ ๊ตฌํ•œ๋‹ค

TOP 5 ํšŒ์› ์ฐพ๊ธฐ ์„ค๊ณ„ ๋ฐ ๊ตฌํ˜„

์ปฌ๋Ÿผ๋ช… ํƒ€์ž… ์ค‘๋ณตํ—ˆ์šฉ ์„ค๋ช…
id Long X ํ…Œ์ด๋ธ” ID(PK)
userId Long X ํšŒ์› ID(FK)
totalTime Long O API ์ด ์‚ฌ์šฉ์‹œ๊ฐ„

ApiUseTime ์ƒ์„ฑ

ApiUseTimeRepository ์ƒ์„ฑ

ProductController ์‚ฌ์šฉ์‹œ๊ฐ„ ๊ธฐ๋ก ์ถ”๊ฐ€

(๊ด€๋ฆฌ์ž) ํšŒ์›๋ณ„ API ์ด ์‚ฌ์šฉ์‹œ๊ฐ„ ์กฐํšŒ API ์„ค๊ณ„ ๋ฐ ๊ตฌํ˜„

๊ธฐ๋Šฅ ๋ฉ”์„œ๋“œ URL ์„ค๋ช…
API ์ด ์‚ฌ์šฉ์‹œ๊ฐ„ ์กฐํšŒ GET /api/use/time ํšŒ์›๋ณ„ API ์ด ์‚ฌ์šฉ์‹œ๊ฐ„ ์กฐํšŒ
(๊ด€๋ฆฌ์ž์šฉ)

ApiUseTimeController ์ƒ์„ฑ

 

AOP๋ž€?

๊ฐ API ๋ณ„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•˜๋Š” ์ฃผ์š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ œ์™ธํ•œ ๋ถ€๊ฐ€๊ธฐ๋Šฅ์„ ๋ชจ๋“ˆํ™”ํ•˜์—ฌ ๋ถ€๊ฐ€๊ธฐ๋Šฅ ์ค‘์‹ฌ์œผ๋กœ ์„ค๊ณ„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ

~ ์Šคํ”„๋ง์ด ์ œ๊ณตํ•˜๋Š” AOP

AOP๋ฅผ ์‚ฌ์šฉํ•ด ๋ชจ๋“  ์ปจํŠธ๋กค๋Ÿฌ์— ๋ถ€๊ฐ€๊ธฐ๋Šฅ ์ถ”๊ฐ€

package com.sparta.myselectshop.aop;

import com.sparta.myselectshop.entity.ApiUseTime;
import com.sparta.myselectshop.entity.User;
import com.sparta.myselectshop.repository.ApiUseTimeRepository;
import com.sparta.myselectshop.security.UserDetailsImpl;
import lombok.RequiredArgsConstructor;
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class UseTimeAop {

    private final ApiUseTimeRepository apiUseTimeRepository;

    @Around("execution(public * com.sparta.myselectshop.controller..*(..))")
    public synchronized 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);

            }
        }
    }
}

AOP ์ ์šฉ ์ „

AOP ์ ์šฉ ํ›„

์Šคํ”„๋ง AOP ์–ด๋…ธํ…Œ์ด์…˜์˜ ์ข…๋ฅ˜

1. @Aspect

์Šคํ”„๋ง ๋นˆ ํด๋ž˜์Šค์— ์ ์šฉ๊ฐ€๋Šฅ

2. ์–ด๋“œ๋ฐ”์ด์Šค์˜ ์ข…๋ฅ˜ ~ AOP ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๋Š” ์‹œ์ ์„ ์ง€์ •ํ•ด์ค€๋‹ค

- @Around : 'ํ•ต์‹ฌ๊ธฐ๋Šฅ' ์ˆ˜ํ–‰ ์ „๊ณผ ํ›„(@Before + @After)

- @Before : 'ํ•ต์‹ฌ๊ธฐ๋Šฅ' ์ˆ˜ํ–‰ ์ „(ex : Client์˜ ์ž…๋ ฅ๊ฐ’ Vaildation ์ˆ˜ํ–‰)

- @After : 'ํ•ต์‹ฌ๊ธฐ๋Šฅ' ์ˆ˜ํ–‰ ์„ฑ๊ณต/์‹คํŒจ ์—ฌ๋ถ€์™€ ๊ด€๊ณ„์—†์ด ์–ธ์ œ๋‚˜ ๋™์ž‘ (try, catch์˜ finally()์™€ ๊ฐ™์€ ๋™์ž‘ ๋ฐฉ์‹)

- @AfterReturning : 'ํ•ต์‹ฌ๊ธฐ๋Šฅ' ํ˜ธ์ถœ ์„ฑ๊ณต์‹œ ๋™์ž‘ํ•˜์—ฌ ํ•จ์ˆ˜์˜ Return๊ฐ’ ์‚ฌ์šฉ๊ฐ€๋Šฅ

- @AfterThrowing : 'ํ•ต์‹ฌ๊ธฐ๋Šฅ' ํ˜ธ์ถœ ์‹คํŒจ์‹œ, ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ์—๋งŒ ๋™์ž‘ (ex : ์˜ˆ์™ธ๋ฐœ์ƒ์‹œ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ํ†ต์ง€๊ธฐ๋Šฅ)

3. ํฌ์ธํŠธ์ปท ~ AOP ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๋Š” ์žฅ์†Œ๋ฅผ ์ •ํ•ด์ค€๋‹ค

์˜ˆ์ œ -> @์–ด๋“œ๋ฐ”์ด์Šค(ํฌ์ธํŠธ์ปท)์˜ ํ˜•ํƒœ

execution(

modifiers-pattern? 

return-type-pattern declaring-type-pattern? 

method-name-pattern(param-pattern) throws-pattern?)โ€‹
@Around("execution(public * com.sparta.springcore.controller..*(..))")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable { ... }

modifiers-pattern : pubilc, private, *

return-type-pattern : void, String, List<String>, *

declaring-type-pattern : ํด๋ž˜์Šค๋ช…(ํŒจํ‚ค์ง€๋ช… ํ•„์š”)

~ com.sparta.springcore.controller.* : controller ํŒจํ‚ค์ง€์˜ ๋ชจ๋“  ํด๋ž˜์Šค์— ์ ์šฉ

~ com.sparta.springcore.controller.. : controller ํŒจํ‚ค์ง€ ๋ฐ ํ•˜์œ„ ํŒจํ‚ค์ง€์˜ ๋ชจ๋“  ํด๋ž˜์Šค๊นŒ์ง€ ์ ์šฉ

method-name-pattern(param-pattern)

ํ•จ์ˆ˜๋ช…

addFolders : addFolders() ํ•จ์ˆ˜์—๋งŒ ์ ์šฉ

add* : add๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋ชจ๋“  ํ•จ์ˆ˜์— ์ ์šฉ

ํŒŒ๋ผ๋ฏธํ„ฐ ํŒจํ„ด

(com.sparta.springcore.dto.FolderRequestDto) - FolderRequestDto ์ธ์ˆ˜์—๋งŒ ์ ์šฉ

() - ์ธ์ˆ˜ ์—†์Œ

(*) - ํƒ€์ž… ์ƒ๊ด€์—†์ด ์ธ์ˆ˜ 1๊ฐœ

(..) - ํƒ€์ž… ์ƒ๊ด€์—†์ด ์ธ์ˆ˜ 1~N๊ฐœ

728x90

'Spring๐Ÿƒ' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

Spring Transaction  (0) 2022.12.29
Spring Exception  (0) 2022.12.29
ํ…Œ์ŠคํŠธ ์ฝ”๋“œ  (0) 2022.12.27
OAuth2  (0) 2022.12.27
์Šคํ”„๋ง ์ˆ™๋ จ : Project MySelectShop (3)  (0) 2022.12.15