본문 바로가기

카테고리 없음

스프링 AOP,관련 어노테이션, JoinPoint 정리 완료

🤔 AOP(Aspect-Oriented Programming)란 ? 

관점 지향 프로그래밍을 뜻함
공통적으로 사용하는 코드(로깅, 트랜잭션, 보안 검사 등)를 깔끔하게 분리해서 관리하는 방법

💡 왜 AOP가 필요할까?

예를 들어 모든 서비스 메서드마다 로그 찍는 코드가 있다면?

 

모든 곳에 저 로그 넣으면… 중복 + 유지보수 힘듦 → 이걸 한 곳에서 해결하는 게 AOP

 

✅ 스프링 AOP 동작 방식 

스프링은 프록시 패턴을 사용해서
원래 객체 앞에 가짜(프록시) 객체를 둬서
메서드 실행 전/후에 부가기능을 추가

 

> 의미는 이렇다는데 나중에 추가로 공부해봐야겠.

💠 핵심 태그들

@Aspect 이 클래스는 AOP 기능을 가진 클래스임을 명시
@Around 대상 메서드 실행 전/후 모두 제어
@Before 메서드 실행 실행
@After 메서드 실행 무조건 실행
@AfterReturning 메서드 정상 종료 후 실행
@AfterThrowing 예외 발생 시 실행

1. @Aspect

이 클래스는 AOP 기능을 가진 클래스임을 명시

2. @Around

대상 메서드 실행 전/후 모두 제어 + 예외 발생 시 도 제어 함

 

좀 있다 나올 ProceedingJoinPoint와 필수로 같이 사용하는데 ProceedingJoinPoint.proceed()로 타겟 메서드를 실행 가능
이 메소드 실행 전,후로 나눠서 제어한다

 

사용방식은 위의 사진처럼 "execution()" 형식

 /**
     * 설명 @Around * -> 와일드 카드 모든 값 리턴 즉 Object org.뭐시기 -> 경로, deleteComment(..)의 .. 와일드 카드 0개 이상의 매개변수
     *
     * @param point 대상 메서드 실행을 제어할 때 사용
     * @return 응답 본문
     */
    @Around("execution(* org.example.expert.domain.comment.controller.CommentAdminController.deleteComment(..))")
    public Object deleteCommentAuthCheck(ProceedingJoinPoint point) throws Throwable {
        return setLog(point);
    }

 

아래 와일드 카드를 보며 어떻게 대상 메소드를 지정하는지 보면 된다

✅ 와일드 카드

표현식의미

* "하나의 요소"를 의미 (예: 메서드 이름, 리턴 타입)
.. "0개 이상"의 요소를 의미 (예: 패키지 깊이 or 파라미터 개수)

🔍 자세히 비교

1. * : 하나의 아무거나

리턴 타입 모든 리턴 타입 execution(* com.example.MyService.myMethod(..))
메서드 이름 어떤 이름이든 execution(* com.example.MyService.*(..))

리턴 타입은 어떤 리턴타입을 가지는 메소드를 대상할 지 정하는 것 즉 *는 모두

2. .. : 0개 이상 / 가변 길이

위치의미예시
패키지 경로 하위 패키지 전부 com.example..* → com.example.service, com.example.service.sub, 등
파라미터 0개 이상 인자 (..) → (), (String), (String, int) 모두 매칭

파라미터는 어떤 파라미터를 가지는 메소를 대상으로 하는지 정하는 것 ..은 모두

 

com.example.. 하면 하위 패키지 전부 

🔥 어노테이션 사용도 가능

@Around(@annotation(어노테이션 경로)) 형식으로도 사용가능

커스텀 어노테이션 만들고 해당 어노테이션이 적용된 메소드만 aop를 적용하겠다는 의미 

 

 

✅ JoinPoint

스프링 AOP에서 Advice가 적용될 수 있는 지점 (메서드 호출 등)을 의미하는 개념

 

✅ 스프링에서의 JoinPoint와 ProceedingJoinPoint 차이

 

JoinPoint 메서드 정보, 파라미터 등 확인 가능. @Before, @After 등에서 사용
ProceedingJoinPoint JoinPoint 확장형으로, proceed()로 실제 메서드 실행 가능. @Around에서만 사용 가능

 

✅ ProceedingJoinPoint

  • JoinPoint를 상속한 인터페이스
  • 유일하게 proceed() 메서드가 있음 → 타겟 메서드 직접 실행
  • @Around에서만 사용 가능

🔎 ProceedingJoinPoint 주요 기능

🧩 주요 메서드 정리

메서드설명
Object proceed() 타겟 메서드 실행
Object[] getArgs() 타겟 메서드에 전달된 인자 값들
Signature getSignature() 실행될 메서드의 시그니처(이름, 리턴타입 등)
Object getTarget() 실제 대상 객체 (예: UserService 인스턴스)
Object getThis() 프록시 객체 (스프링 AOP가 감싼 proxy)
SourceLocation getSourceLocation() 소스 코드 위치 (디버깅용)
StaticPart getStaticPart() 정적인 정보 (시그니처 등 요약본)

📖 사용예시

    public Object setLog(ProceedingJoinPoint point) throws Throwable {

        // 타겟 메소드 실행전
        HttpServletRequest request = // 스프링이 현재 요청 컨텍스트에서 자동으로 꺼내줌
            ((ServletRequestAttributes) Objects.requireNonNull(
                RequestContextHolder.getRequestAttributes())).getRequest();

        Object[] arg = point.getArgs(); // 대상 메소드의 매개변수에 들어온 값 가져옴 배열형태
        log.info("요청한 사용자의 ID -> {}", arg[0]);
        log.info("API 요청 시각 -> {}", LocalDateTime.now());
        log.info("API 요청 URL -> {}", request.getRequestURI());
        log.info("요청 본문 -> {}", arg);
        Object responseObj = point.proceed(); // 대상 메소드 실행
        log.info("응답 본문 -> {}", responseObj); // 타겟 메소드 실행 후
        return responseObj;
        
    }