AOP

2024. 10. 31. 12:36·TIL

AOP (Aspect Oriented Programming)

 

AOP는 부가기능을 핵심 기능에서 분리해 한 곳으로 관리하도록 하고, 이 부가 기능을 어디에 적용할지 선택하는 기능을 합한 하나의 모듈입니다.

 

AOP 용어

  • 조인 포인트
    • 어드바이스가 적용될 수 있는 위치로, AOP를 적용할 수 있는 모든 지점
  • 포인트컷
    • 조인 포인트 중에서 어드바이스를 어디에 적용할 지, 적용하지 않을 지 위치를 판단하는 필터링 기능
  • 타겟
    • 어드바이스를 받는 객체, 포인트컷으로 결정
  • Advice
    • 부가 기능
  • Aspect
    • 어드바이스  + 포인터컷을 모듈화 한 것
  • Advisor
    • 하나의 어드바이스와 하나의 포인트 컷으로 구성

AOP 적용 방식

  • 컴파일 시점
  • 클래스 로딩 시점
  • 런타임 시점

컴파일 시점과 클래스 로딩 시점 적용 방식은 AspectJ 프레임 워크를 직접 사용해야 하지만  AspectJ를 학습하기가 번거로워 주로 런타임 시점 적용 방식을 사용하는 스프링 AOP를 사용한다.

 

 

Advice 종류

@Around 핵심기능 수행 전과 후 (@Before + @After)
@Before 핵심기능 호출 전
@After 핵심기능 수행 성공/실패 여부 상관 없이 언제나 동작
@AfterReturning 핵심기능 수행 성공 시 (함수의 return 값 사용가능)
@AfterThrowing 핵심기능 수행 실패 시. 즉 예외가 발생한 경우 동작

 

 

@Around 어드바이스를 사용할 경우 메서드의 파라미터로 "ProceedingJoinPoint"를 꼭 넣어줘야 한다.

 

ProceedingJoinPoint의 proceed()는 다음 어드바이스나 타겟을 호출 하는 것으로, 꼭 proceed() 메서드를 호출해줘야한다.

 

이 외에도 ProcedingJoinPoist 인터페이스가 제공하는 메서드를 사용하여 호출되는 객체의 정보나 실행되는 메서드의 정보를 알 수 있다.

아래는 ProcedingJoinPoist 인터페이스가 제공하는 메서드의 일부이다.

Signature get Signature() 호출되는 메서드에 대한 정보를 반환
Object getTarget() 대상 객체를 반환
String getName() 메서드의 이름을 반환
String toLongString() 메서드를 완전하게 표현한 문장을 반환

 

직접 사용해보기

Spring AOP를 사용하기 위해서는 gradle에 의존성을 추가해줘야한다.

implementation 'org.springframework.boot:spring-boot-starter-aop'

 

각각의 컨트롤러로 요청이 들어올 때 마다 요청 시각, Url, 사용자 Id, requestBody와 responeBody를 로그에 찍히도록 구현하였다.

@Slf4j(topic = "TodoAop")
@Aspect // 해당 클래스가 Aspect라는 것을 명시
@Component // 스프링 빈으로 등록
@RequiredArgsConstructor
public class TodoAop {
	
    // user.controller 패키지의 모든 클래스
    @Pointcut("execution(* com.sparta.todo.domain.user.controller..*(..))")
    public void user() {
    }

	// comment.controller 패키지의 모든 클래스
    @Pointcut("execution(* com.sparta.todo.domain.comment.controller..*(..))")
    public void comment() {
    }

	// manager.controller 패키지의 모든 클래스
    @Pointcut("execution(* com.sparta.todo.domain.manager.controller..*(..))")
    public void manager() {
    }

	// todo.controller 패키지의 모든 클래스
    @Pointcut("execution(* com.sparta.todo.domain.todo.controller..*(..))")
    public void todo() {
    }
    
    @Around("user() || todo() || comment() || manager()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        LocalDateTime requestTime = LocalDateTime.now();
        DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
        String formattedDate = requestTime.format(format);

        HttpServletRequest request =((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest();
        Long userId = (Long) request.getAttribute("userId");
        log.info("Request : {} {} {} {}" , request.getMethod(),request.getRequestURI(),params(joinPoint),formattedDate);
        log.info("사용자 Id : {}", userId);

        Object obj = joinPoint.proceed();

        request =((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest();

        log.info("Response : {} {}", request.getRequestURI(), obj);
        return obj;
    }

    private Map<String, Object> params(JoinPoint joinPoint) {
        CodeSignature codeSignature = (CodeSignature) joinPoint.getSignature();
        String[] paramNames = codeSignature.getParameterNames();
        Object[] paramValues = joinPoint.getArgs();
        Map<String, Object> params = new HashMap<>();
        for (int i = 0; i < paramNames.length; i++) {
            params.put(paramNames[i], paramValues[i]);
        }
        return params;
    }
 }

 

Todo 게시글 저장 요청 시 

위 사진처럼 요청 시각과 사용자 Id, 요청 uri, request, responseBody가 로그에 찍힌다 !

 

'TIL' 카테고리의 다른 글

미리 서명된 URL(Pre-signed url) 사용해보기  (0) 2024.11.11
GCS를 이용한 이미지 업로드 기능 구현  (2) 2024.11.08
기능 개선 과제  (0) 2024.10.31
Todo 프로젝트 리팩토링 하기  (0) 2024.10.30
뉴스피드 프로젝트 리팩토링  (1) 2024.10.25
'TIL' 카테고리의 다른 글
  • 미리 서명된 URL(Pre-signed url) 사용해보기
  • GCS를 이용한 이미지 업로드 기능 구현
  • 기능 개선 과제
  • Todo 프로젝트 리팩토링 하기
haseung22
haseung22
haseung22 의 블로그 입니다.
  • haseung22
    haseung22의 블로그
    haseung22
  • 전체
    오늘
    어제
    • 분류 전체보기 (56)
      • TIL (39)
      • 프로그래머스 (8)
      • 프로젝트 (5)
      • 면접 대비 (4)
        • 자료구조 (3)
        • Java (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    내배캠
    알고리즘
    뉴스피드
    JPA
    회고
    과제
    docker
    til
    querydsl
    팀 프로젝트
    계산기
    Spring Boot
    리팩토링
    Spring
    티스토리챌린지
    프로그래머스
    공부
    오블완
    java
    자료구조
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.1
haseung22
AOP
상단으로

티스토리툴바