관리 메뉴

ballqs 님의 블로그

[Spring] AOP 동작 흐름 및 패턴 이해 본문

코딩 공부/Spring

[Spring] AOP 동작 흐름 및 패턴 이해

ballqs 2024. 9. 10. 08:16

예전에 AOP에 관한 글을 작성했는데 그부분은 아주 간단하게 사용하는 방법에 대해서였다.

그러나 현재 같은 AOP를 다시 작성하게 된 이유는 동작 흐름이 어떻게 흘러가는지?

패턴은 어떤식으로 되는지 배웠기 때문에 작성한다.

 

이전 AOP 작성글 : https://ballqs.tistory.com/44


AOP의 동작 흐름

개념적 이해

스프링 실제 동작


시퀀스 다이어그램(Sequence Diagram)

AOP 적용 전

 

AOP 적용 후

  • Spring이 프록시(가짜 혹은 대리) 객체를 중간에 삽입한다.
  • DispatcherServlet 과 ProductController 입장에서는 변화가 전혀 없다.
    • 호출되는 함수의 input, output 이 완전 동일하다
    • "joinPoint.proceed()" 에 의해서 원래 호출하려고 했던 함수, 인수(argument) 가 전달된다.
    • → createProduct(requestDto);

포인트컷 Expression 형태

execution(modifiers-pattern? return-type-pattern declaring-type-pattern? 
method-name-pattern(param-pattern) throws-pattern?)

 

? 는 생략 가능

포인트컷 예제

@Around("execution(public * com.sparta.myselectshop.controller..*(..))")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable { ... }
  • modifiers-pattern
    • public, private, *
  • return-type-pattern
    • void, String, List<String>, *****
  • declaring-type-pattern
    • 클래스명 (패키지명 필요)
    • com.sparta.myselectshop.controller.* - controller 패키지의 모든 클래스에 적용
    • com.sparta.myselectshop.controller.. - controller 패키지 및 하위 패키지의 모든 클래스에 적용
  • method-name-pattern(param-pattern)
    • 함수명
      • addFolders : addFolders() 함수에만 적용
      • add* : add 로 시작하는 모든 함수에 적용
    • 파라미터 패턴 (param-pattern)
      • (com.sparta.myselectshop.dto.FolderRequestDto) - FolderRequestDto 인수 (arguments) 만 적용
      • () - 인수 없음
      • (*) - 인수 1개 (타입 상관없음)
      • (..) - 인수 0~N개 (타입 상관없음)
  • @Pointcut
    • 포인트컷 재사용 가능
    • 포인트컷 결합 (combine) 가능
@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() {
		...
	}	
}

패턴 사용 예제

@Slf4j(topic = "SpringAop")
@Aspect
@RequiredArgsConstructor
@Component
public class SpringAop {

    private final JwtUtil jwtUtil;

    @Pointcut("execution(* org.example.expert.domain.comment.controller.CommentAdminController.deleteComment(..))")
    private void checkDeleteComment() {}

    @Pointcut("execution(* org.example.expert.domain.user.controller.UserAdminController.changeUserRole(..))")
    private void checkChangeUserRole() {}

    @Around("checkDeleteComment() || checkChangeUserRole()")
    public Object check(ProceedingJoinPoint joinPoint) throws Throwable {
        LocalDateTime dt = LocalDateTime.now();
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        // request.getAttribute("userId")로도 처리 가능
        String token = request.getHeader(HttpHeaders.AUTHORIZATION);
        Claims claims = jwtUtil.extractClaims(token);

        try {
            Object output = joinPoint.proceed();
            return output;
        } finally {
            log.info("요청한 사용자 ID : " + claims.getSubject() + ", API 요청시간 : " + dt + ", API 요청 URL : " + request.getRequestURI());
        }
    }
}

마무리

아무래도 유데미 강의를 보면서 불분명했던 부분이 내배캠 강의를 통해 동작흐름의 시각화와 패턴에 대해 상세히 알려줘서 이젠 어떻게 사용하면 되는지 눈에 보이는 듯 했다. 이래서 많은 강의를 보면서 공부하나 보다...

인프런 강의도 돈만 있었다면 샀을듯...