ballqs 님의 블로그
[Spring] AOP 동작 흐름 및 패턴 이해 본문
예전에 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());
}
}
}
마무리
아무래도 유데미 강의를 보면서 불분명했던 부분이 내배캠 강의를 통해 동작흐름의 시각화와 패턴에 대해 상세히 알려줘서 이젠 어떻게 사용하면 되는지 눈에 보이는 듯 했다. 이래서 많은 강의를 보면서 공부하나 보다...
인프런 강의도 돈만 있었다면 샀을듯...
'코딩 공부 > Spring' 카테고리의 다른 글
[Spring] CORS란? (0) | 2024.09.14 |
---|---|
[Spring] 테스트 코드 심화(Controller , Service) (0) | 2024.09.11 |
[Spring] Redis 적용 (Window 환경) (0) | 2024.09.08 |
[Spring] CustomException , ErrorCode 작성 및 적용 (0) | 2024.09.05 |
[Spring] @Query를 사용하다 생긴 문제 , Enum 활용 , Java 설정 파일 (0) | 2024.09.04 |