๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
BE/๐Ÿƒ Spring

[Spring Boot] AOP ์‚ฌ์šฉ ๋ฐฉ๋ฒ•๊ณผ ์˜ˆ์‹œ์ฝ”๋“œ

by ํ‹ด๋”” 2024. 11. 18.
๋ฐ˜์‘ํ˜•

 

์˜์กด์„ฑ ์ถ”๊ฐ€

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-aop'
}

 

 

์‚ฌ์šฉ ๋ฐฉ์‹

  1. Aspect ์ •์˜ : @Aspect ์• ๋„ˆํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•ด์„œ Aspect ํด๋ž˜์Šค๋ฅผ ์ •์˜ํ•œ๋‹ค
  2. Advice ์ ์šฉ : @Before, @After, @Around ๋“ฑ ๋‹ค์–‘ํ•œ Advice๋ฅผ ๋ฉ”์„œ๋“œ์— ์ ์šฉํ•œ๋‹ค. ํŠน์ • ์‹œ์ ์— ์–ด๋–ค ์‹คํ–‰ ๋กœ์ง์„ ์‹คํ–‰ํ• ์ง€ ์ •์˜ํ•œ๋‹ค.
  3. Pointcut ์„ค์ • : execution ํ‘œํ˜„์‹ ๋“ฑ์„ ํ†ตํ•ด ํŠน์ • ๋ฉ”์„œ๋“œ, ํŒจํ‚ค์ง€ ๋“ฑ์—๋งŒ Aspect๊ฐ€ ์ ์šฉ๋˜๋„๋ก ์„ค์ •ํ•œ๋‹ค
  4. AOP ํ™œ์„ฑํ™” : @EnableAspectJAuotProxy ์• ๋„ˆํ…Œ์ด์…˜์„ Spring Boot ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํด๋ž˜์Šค์— ์ถ”๊ฐ€ํ•ด AOP๋ฅผ ํ™œ์„ฑํ™” ํ•œ๋‹ค

 

@EnableAspectJAutoProxy

  • ์Šคํ”„๋ง ์ปจํ…์ŠคํŠธ ๋‚ด์—์„œ AspectJ AOP ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ์• ๋„ˆํ…Œ์ด์…˜
  • AOP ํ”„๋ก์‹œ ๋นˆ์„ ์ž๋™์œผ๋กœ ๋“ฑ๋กํ•˜๊ณ  AOP๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋จ
  • ํ•ด๋‹น ์• ๋„ˆํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ AspectJ AOP ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ

 

๋™์ž‘๊ณผ์ •

  • AOP๊ฐ€ ์ ์šฉ๋œ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์‹œ Spring์€ ์ž๋™์œผ๋กœ ์„ค์ •๋œ Advice๋ฅผ ์‹คํ–‰ 
  • ์˜ˆ๋ฅผ ๋“ค์–ด @Around Advice๊ฐ€ ์„ค์ •๋œ ๋ฉ”์„œ๋“œ๋Š” AOP ํ”„๋ก์‹œ๊ฐ€ ํ•ด๋‹น ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์„ ๊ฐ€๋กœ์ฑˆ ํ›„ ๋ฉ”์„œ๋“œ ์‹คํ–‰ ์ „ํ›„ ์ง€์ •๋œ ๋กœ์ง์„ ์ˆ˜ํ–‰

 

์‹œ๊ฐ„ ์ธก์ • Aspect ์˜ˆ์ œ

 

  • com.youable.aop_example.service.BankService์˜ ๋ฉ”์†Œ๋“œ๊ฐ€ ์‹คํ–‰๋  ๋•Œ ๋กœ๊น… ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์˜ˆ์ œ
package com.youable.aop_example.service;

@Service
@RequiredArgsConstructor
public class BankService {
    private final AccountRepository accountRepository;
    private final TransactionRepository transactionRepository;

    public String registAccount(
            RegistAccountRequest request
    ) {
        String accountNumber = UniqueValueGenerator.getAccountNumber();
        Account account = request.of(accountNumber, request);
        accountRepository.save(account);
        return accountNumber;
    }

    public Transaction deposit(TransactionRequest request) {
        Account account = accountRepository.findByAccountNumber(request.getAccountNumber())
                .orElseThrow(() -> new RuntimeException("account not found"));
		// ์ƒ๋žต
        return transaction;
    }

    public Transaction withdrawal(TransactionRequest request) {
        Account account = accountRepository.findByAccountNumber(request.getAccountNumber())
                .orElseThrow(() -> new RuntimeException("account not found"));
		// ์ƒ๋žต
        return transaction;
    }
}
  • registAccount, deposit, withdrawal ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Œ
@Aspect
@Component
@Slf4j
public class LoggingAspect {
    @Around("execution(* com.youable.aop_example.service.BankService.*(..))")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();

        Object result = joinPoint.proceed();

        long executionTime = System.currentTimeMillis() - start;
        log.info("์‹คํ–‰ ๋œ ๋ฉ”์†Œ๋“œ ๋ช… : {},  ์‹คํ–‰ ์‹œ๊ฐ„ :  {} ms",
                joinPoint.getSignature().getName(), executionTime);

        return result;
    }
}
  • ProceedingJoinPoint๋กœ ๋ฉ”์„œ๋“œ ์ด๋ฆ„์„ ์–ป์„ ์ˆ˜ ์žˆ์Œ
  • BankService์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด AOP ์„ค์ •์— ๋”ฐ๋ผ @Around Advice๊ฐ€ ์‹คํ–‰๋จ
  • ProceedingJoinPoint์˜ proceed() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์‹ค์ œ ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋จ
  • proceed์— ์˜ํ•ด ์‹ค์ œ ๋ฉ”์„œ๋“œ๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด ๋ฉ”์„œ๋“œ ํ›„์† ์ž‘์—…์œผ๋กœ ๋Œ์•„์™€ ์ดํ›„ ๋กœ์ง์„ ์ˆ˜ํ–‰
์‹คํ–‰ ๋œ ๋ฉ”์†Œ๋“œ ๋ช… : registAccount,  ์‹คํ–‰ ์‹œ๊ฐ„ :  30 ms
  • ์‹คํ–‰ ๊ฒฐ๊ณผ

๋ฉ”์„œ๋“œ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ

@Aspect
@Component
@RequiredArgsConstructor
@Slf4j
public class SecurityAspect {
    private final AccountRepository accountRepository;
    @Before("execution(* com.youable.aop_example.service.BankService.withdrawal(..))")
    public void checkSecurity(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        TransactionRequest transaction = (TransactionRequest) args[0];
       log.warn("Large amount withdrawal detected!");
       Account account = accountRepository.findByAccountNumberAndOwnerNameAndPassword(transaction.getAccountNumber(), transaction.getOwnerName(), transaction.getPassword())
               .orElseThrow(() -> new RuntimeException("fail authorization"));

    }
}
  • Advice์‹คํ–‰์‹œ ๋ฉ”์„œ๋“œ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ JoinPoint๋กœ ๋ถ€ํ„ฐ ์–ป์„ ์ˆ˜ ์žˆ์Œ

 

728x90
๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€