AOP 적용 예제

박찬우·2024년 2월 17일

스프링

목록 보기
75/88

로그 AOP

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Trace {
}
@Slf4j
@Aspect
public class TraceAspect {

    @Before("@annotation(hello.aop.exam.annotation.Trace)")
    public void doTrace(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        log.info("[trace] {} args={}", joinPoint.getSignature(), args);
    }
}

재시도 AOP

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Retry {
	// 재시도 횟수 제한
    int value() default 3;
}
@Slf4j
@Aspect
public class RetryAspect {
    @Around("@annotation(retry)")
    public Object doRetry(ProceedingJoinPoint joinPoint, Retry retry) throws
            Throwable {
        log.info("[retry] {} retry={}", joinPoint.getSignature(), retry);
        int maxRetry = retry.value();
        Exception exceptionHolder = null;
        for (int retryCount = 1; retryCount <= maxRetry; retryCount++) {
            try {
                log.info("[retry] try count={}/{}", retryCount, maxRetry);
                // 여기서 오류가 나면 오류를 잡고 2번째 루프를 실행
                return joinPoint.proceed();
            } catch (Exception e) {
                exceptionHolder = e;
            }
        }
        throw exceptionHolder;
    }
}

리포지토리, 서비스

@Repository
public class ExamRepository {

    private static int seq = 0;

    /**
     * 5번에 1번 실패하는 요청
     */
    @Trace
    public String save(String itemId) {
        seq++;
        if (seq % 5 == 0) {
            throw new IllegalStateException("예외 발생");
        }
        return "ok";
    }

}
@Service
@RequiredArgsConstructor
public class ExamService {
    private final ExamRepository examRepository;

    @Trace
    @Retry(value = 4)
    public void request(String itemId) {
        examRepository.save(itemId);
    }
}

TEST

@SpringBootTest
@Import({TraceAspect.class, RetryAspect.class})
public class ExamTest {
    @Autowired
    ExamService examService;

    @Test
    void test() {
        for (int i = 0; i < 5; i++) {
            examService.request("data" + i);
        }
    }
}

결과

  • 5의 배수마다 예외를 던지는 테스트
  • 일단 모든 메소드 실행 시 [Trace] 로그가 찍히도록 AOP 지정
  • 만약 5의 배수가 나와 예외가 발생한 경우 재시도를 한다
  • 예)
    • 0, 1, 2, 3 까지는 정상작동
    • 4 부터 seq=5 이므로 예외 발생
    • 재시도 AOP에서 예외를 잡은 후 재시도
    • 재시도 시 seq=6 이므로 예외가 발생하지 않고 정상 작동

profile
진짜 개발자가 되어보자

0개의 댓글