API

Spring AOP 설명(Annotaion, Class) 및 예제

letsDoDev 2025. 1. 17. 17:27

어노테이션 먼저 정리

1. @Before

  • 설명: 지정된 포인트컷 이전에 실행되는 어드바이스

2. @After

  • 설명: 지정된 포인트컷 후에 실행되는 어드바이스 메소드 실행 여부와 관계없이 항상 실행

3. @AfterReturning

  • 설명: 지정된 포인트컷의 메소드가 정상적으로 실행된 후에 실행되는 어드바이스 메소드가 예외 없이 정상적으로 종료되었을 때만 실행

4. @AfterThrowing

  • 설명: 지정된 포인트컷의 메소드가 예외를 던졌을 때 실행

5. @Around

  • 설명: 지정된 포인트컷 전후로 실행되며, 메소드의 실행을 제어 @Before와 @After를 합친 효과를 제공 ProceedingJoinPoint를 이용하여 메소드 실행을 직접 제어 가능

6. @Pointcut

  • 설명: 어드바이스가 적용될 포인트컷 표현식을 정의하는 어노테이션 다른 어드바이스에서 사용될 수 있도록 포인트컷을 재사용 가능 일종의 AOP 타겟 alias 한다고 생각하면 쉽다

7. @EnableAspectJAutoProxy

  • 설명: Spring에서 AOP 기능을 활성화하려면 @EnableAspectJAutoProxy 어노테이션을 추가해야 한다.
    EnableAspectJAutoProxy는 Spring AOP를 활성화하고, AspectJ 스타일의 AOP 기능(포인트컷, 어드바이스 등)을 프록시 기반으로 사용할 수 있게 해주는 어노테이션 으로
    스프링 부트에서는 spring-boot-starter-aop 의 영향으로 저 어노테이션을 붙인 config 파일을 생성하지 않아도 된다
    본인은 해당 게시물에서 파일을 생성하지 않고 예제를 생성하였다.

  • 사용할 경우 예시 ↓
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
    // 빈 정의
}

 

 


@Pointcut 표현식에서 사용되는 주요 키워드

  • execution(): 메소드 실행 시점을 포인트컷으로 지정
    • 예시: execution(* com.example.service.*.*(..)) (모든 메소드)
  • within(): 특정 클래스나 패키지 내에서 실행되는 메소드에 적용
    • 예시: within(com.example.service.*) (service 패키지 내 모든 클래스의 메소드)
  • args(): 메소드의 파라미터 타입을 기준으로 포인트컷을 지정
    • 예시: args(java.lang.String) (String 타입 파라미터를 받는 메소드)
  • @annotation(): 특정 어노테이션이 적용된 메소드에 적용
    • 예시: @annotation(org.springframework.transaction.annotation.Transactional) (Transactional 어노테이션이 적용된 메소드)
  • this(), target(): 프록시 객체와 대상 객체를 기준으로 포인트컷을 설정

 

 


[프로젝트 구조]

위 구조에서 보이는 LogHelper 클래스가

AOP 포인트컷과 메소드를 정의할 클래스

 

- SampleController

package com.proxy.study_aspectj.sample.controller;

import com.proxy.study_aspectj.sample.service.SampleService;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class SampleController {

     private final SampleService sampleService;

    public SampleController(SampleService sampleService) {
        this.sampleService = sampleService;
    }

    /**
     *  모든 샘플데이터 가져오기
     */
    @GetMapping("/samples")
    public ResponseEntity<?> getAllSample() {
        return ResponseEntity.status(HttpStatus.OK).body(sampleService.getAllSample());
    }

    /**
     * 의도적으로 Exception throw 하기
     */
    @GetMapping("/error")
    public void getError() {
        sampleService.getError();
    }


    /**
     * request header 의 Authrization 이 "pass" 일 때만 데이터 반환 아닐 시 Exceptio throw
     */
    @GetMapping("/getPrivateInfo")
    public ResponseEntity<?> getPrivateInfo(HttpServletRequest request) {
        return ResponseEntity.ok().body(sampleService.getPrivateInfo());
    }
}

 

 

- SampleService

package com.proxy.study_aspectj.sample.service;

import com.proxy.study_aspectj.sample.dto.SampleDto;

import java.util.List;
import java.util.Map;

public interface SampleService {

    public List<SampleDto> getAllSample();

    public void getError();

    public Map getPrivateInfo();
}

 

 

- SampleServiceImpl

package com.proxy.study_aspectj.sample.service;

import com.proxy.study_aspectj.sample.dto.SampleDto;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class SampleServiceImpl implements SampleService {

    @Override
    public List<SampleDto> getAllSample() {
        List<SampleDto> returnObject = new ArrayList<>();

        String title = "sample_title";
        String conent = "sample_content";


        for (int i = 0; i < 10; i++) {
            SampleDto samplteDto = new SampleDto();
            samplteDto.setTitle(title + "_" + (i+1));
            samplteDto.setContent(conent + "_" + (i+1));
            returnObject.add(samplteDto);
        }

        return returnObject;
    }

    @Override
    public void getError() {
        throw new IllegalArgumentException("INTENDED ERROR IS OCCURED");
    }

    @Override
    public Map getPrivateInfo() {
        Map importanatData = new HashMap<>();

        importanatData.put("name", "홍길동");
        importanatData.put("age", 19);
        importanatData.put("phone", "010-0000-0000");

        return importanatData;
    }
}

 

 

- LogHelper

package com.proxy.study_aspectj.sample.util;

import com.proxy.study_aspectj.sample.dto.SampleDto;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.List;

/**
 * SampleService 에서 수행되는 로직 들에 대한 AOP 포인트 컷과 메소드를 정의할 클래스
 */
@Aspect
@Component
public class LogHelper {

    private static final Logger log = LoggerFactory.getLogger(LogHelper.class);

    /*
        [ @Pointcut 표현식에서 사용되는 주요 키워드 ]
        execution(): 메소드 실행 시점을 포인트컷으로 지정
        예시: execution(* com.example.service.*.*(..)) (모든 메소드)

        within(): 특정 클래스나 패키지 내에서 실행되는 메소드에 적용
        예시: within(com.example.service.*) (service 패키지 내 모든 클래스의 메소드)

        args(): 메소드의 파라미터 타입을 기준으로 포인트컷을 지정
        예시: args(java.lang.String) (String 타입 파라미터를 받는 메소드)

        @annotation(): 특정 어노테이션이 적용된 메소드에 적용
        예시: @annotation(org.springframework.transaction.annotation.Transactional) (Transactional 어노테이션이 적용된 메소드)

        this(), target(): 프록시 객체와 대상 객체를 기준으로 포인트컷을 설정
     */

    // @Pointcut("@annotation(org.springframework.web.bind.annotation.PostMapping)") // 타겟이 어노테이션
    @Pointcut("within(com.proxy.study_aspectj.sample.service.*)") // 타켓이 클래스
    public void getTargetClass () {} // 일종의 alias 화

    @Pointcut("execution(* com.proxy.study_aspectj.sample.service.SampleService.getPrivateInfo(..))") // 타겟이 메소드
    public void getTargetMethod () {};

    /*
    JoinPoint는 현재 실행되고 있는 메소드에 대한 정보를 제공하는 객체 : 주로 메소드 이름, 파라미터, 타겟 객체 등 다양한 정보를 얻을 수 있음
    getSignature(): 현재 실행되는 메소드의 서명(메소드 이름, 반환 타입, 파라미터 타입 등)을 반환
    getArgs(): 메소드의 인자들을 배열로 반환
    getTarget(): 메소드를 실행한 객체를 반환
    getThis(): 프록시 객체를 반환
    */
    
    @Before("getTargetClass()")
    public void before(JoinPoint joinPoint) {
        log.info("BEFORE AOP METHOD IS RUNNING");
    }

    @After("getTargetClass()")
    public void after(JoinPoint joinPoint) {
        log.info("AFTER AOP METHOD IS RUNNING");
    }

    @Around(value = "getTargetClass()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("AROUND AOP METHOD IS START");
        Object returnObject= joinPoint.proceed();
        log.info("AROUND AOP METHOD IS END");

        // 포인트컷 메소드의 반환타입이 void 이든 객체이든 상관없이
        // joinPrint.proceed() 의 결과값을 반환해주야 한다.
        return returnObject;
    }

    @AfterReturning(value = "getTargetClass()", returning = "result") // 타겟 메소드가 리턴값이 있다면 리턴값 반환 후 실행
    public void afterReturnning(List<SampleDto> result) {
        log.info("AFTER_RETURNNING AOP METHOD IS RUNNING");
        log.info("result -> {}", result);
    }

    @AfterThrowing(value = "getTargetClass()", throwing = "exception") // 타겟 메소드가 예외를 던진다면 던진 후 실행
    public void afterThrowing(Exception exception) {
        log.info("AFTER_THROWING AOP METHOD IS RUNNING");
        log.error(exception.getLocalizedMessage());
    }
    
    // 아래는 헤더의 Authorization 도 확인 가능한지 궁금해서 찍어본 것
    @Around(value = "getTargetMethod()")
    public Object authCheckAOP (ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

        log.info("AUTH-CHECK-AOP START");

        // request 요청 값 가져오기 세트로 기억하자
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        String authValue = request.getHeader("Authorization");

        if (authValue.equals("pass")) {
            Object returnObject = proceedingJoinPoint.proceed();
            log.info("AUTH-CHECK-AOP END");
            return returnObject;
        } else {
            log.error("AUCH-CHECK0-AOP IS DETECTING : UNVALID AUTH");
            throw new RuntimeException("AUCH-CHECK0-AOP IS DETECTING : UNVALID AUTH");
        }
    }
}

 


[실행결과]

#1 -  localhost:8080/api/samples : 모든 샘플 데이터 출력시

로그

2025-01-17T16:59:28.084+09:00  INFO 1644 --- [study_aspectj] [nio-8080-exec-3] c.p.study_aspectj.sample.util.LogHelper  : AROUND AOP METHOD IS START
2025-01-17T16:59:28.084+09:00  INFO 1644 --- [study_aspectj] [nio-8080-exec-3] c.p.study_aspectj.sample.util.LogHelper  : BEFORE AOP METHOD IS RUNNING
2025-01-17T16:59:28.084+09:00  INFO 1644 --- [study_aspectj] [nio-8080-exec-3] c.p.study_aspectj.sample.util.LogHelper  : AFTER_RETURNNING AOP METHOD IS RUNNING
2025-01-17T16:59:28.084+09:00  INFO 1644 --- [study_aspectj] [nio-8080-exec-3] c.p.study_aspectj.sample.util.LogHelper  : result -> [SampleDto{title='sample_title_1', content='sample_content_1'}, SampleDto{title='sample_title_2', content='sample_content_2'}, SampleDto{title='sample_title_3', content='sample_content_3'}, SampleDto{title='sample_title_4', content='sample_content_4'}, SampleDto{title='sample_title_5', content='sample_content_5'}, SampleDto{title='sample_title_6', content='sample_content_6'}, SampleDto{title='sample_title_7', content='sample_content_7'}, SampleDto{title='sample_title_8', content='sample_content_8'}, SampleDto{title='sample_title_9', content='sample_content_9'}, SampleDto{title='sample_title_10', content='sample_content_10'}]
2025-01-17T16:59:28.084+09:00  INFO 1644 --- [study_aspectj] [nio-8080-exec-3] c.p.study_aspectj.sample.util.LogHelper  : AFTER AOP METHOD IS RUNNING
2025-01-17T16:59:28.084+09:00  INFO 1644 --- [study_aspectj] [nio-8080-exec-3] c.p.study_aspectj.sample.util.LogHelper  : AROUND AOP METHOD IS END

각 AOP 메소드에 미리 로그 출력 소스를 작성하였기 떄문에 어노테이션별 메소드 실행 시점을 명확하게 확인할 수 있다.


 

#2 -  localhost:8080/api/error : 의도적인 에러 발생시

더보기

2025-01-17T16:59:28.084+09:00  INFO 1644 --- [study_aspectj] [nio-8080-exec-3] c.p.study_aspectj.sample.util.LogHelper  : AROUND AOP METHOD IS START
2025-01-17T16:59:28.084+09:00  INFO 1644 --- [study_aspectj] [nio-8080-exec-3] c.p.study_aspectj.sample.util.LogHelper  : BEFORE AOP METHOD IS RUNNING
2025-01-17T16:59:28.084+09:00  INFO 1644 --- [study_aspectj] [nio-8080-exec-3] c.p.study_aspectj.sample.util.LogHelper  : AFTER_RETURNNING AOP METHOD IS RUNNING
2025-01-17T16:59:28.084+09:00  INFO 1644 --- [study_aspectj] [nio-8080-exec-3] c.p.study_aspectj.sample.util.LogHelper  : result -> [SampleDto{title='sample_title_1', content='sample_content_1'}, SampleDto{title='sample_title_2', content='sample_content_2'}, SampleDto{title='sample_title_3', content='sample_content_3'}, SampleDto{title='sample_title_4', content='sample_content_4'}, SampleDto{title='sample_title_5', content='sample_content_5'}, SampleDto{title='sample_title_6', content='sample_content_6'}, SampleDto{title='sample_title_7', content='sample_content_7'}, SampleDto{title='sample_title_8', content='sample_content_8'}, SampleDto{title='sample_title_9', content='sample_content_9'}, SampleDto{title='sample_title_10', content='sample_content_10'}]
2025-01-17T16:59:28.084+09:00  INFO 1644 --- [study_aspectj] [nio-8080-exec-3] c.p.study_aspectj.sample.util.LogHelper  : AFTER AOP METHOD IS RUNNING
2025-01-17T16:59:28.084+09:00  INFO 1644 --- [study_aspectj] [nio-8080-exec-3] c.p.study_aspectj.sample.util.LogHelper  : AROUND AOP METHOD IS END
2025-01-17T17:01:58.802+09:00  INFO 1644 --- [study_aspectj] [nio-8080-exec-9] c.p.study_aspectj.sample.util.LogHelper  : AROUND AOP METHOD IS START
2025-01-17T17:01:58.802+09:00  INFO 1644 --- [study_aspectj] [nio-8080-exec-9] c.p.study_aspectj.sample.util.LogHelper  : BEFORE AOP METHOD IS RUNNING
2025-01-17T17:01:58.802+09:00  INFO 1644 --- [study_aspectj] [nio-8080-exec-9] c.p.study_aspectj.sample.util.LogHelper  : AFTER_THROWING AOP METHOD IS RUNNING
2025-01-17T17:01:58.802+09:00 ERROR 1644 --- [study_aspectj] [nio-8080-exec-9] c.p.study_aspectj.sample.util.LogHelper  : INTENDED ERROR IS OCCURED
2025-01-17T17:01:58.802+09:00  INFO 1644 --- [study_aspectj] [nio-8080-exec-9] c.p.study_aspectj.sample.util.LogHelper  : AFTER AOP METHOD IS RUNNING
2025-01-17T17:01:58.803+09:00 ERROR 1644 --- [study_aspectj] [nio-8080-exec-9] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.lang.IllegalArgumentException: INTENDED ERROR IS OCCURED] with root cause

java.lang.IllegalArgumentException: INTENDED ERROR IS OCCURED
at cohttp://m.proxy.study_aspectj.sample.service.SampleServiceImpl.getError(SampleServiceImpl.java:33) ~[main/:na]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:57) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:49) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:58) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89) ~[spring-aop-6.2.1.jar:6.2.1]
at cohttp://m.proxy.study_aspectj.sample.util.LogHelper.around(LogHelper.java:69) ~[main/:na]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727) ~[spring-aop-6.2.1.jar:6.2.1]
at cohttp://m.proxy.study_aspectj.sample.service.SampleServiceImpl$SpringCGLIB$0.getError(<generated>) ~[main/:na]
at cohttp://m.proxy.study_aspectj.sample.controller.SampleController.getError(SampleController.java:29) ~[main/:na]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:257) ~[spring-web-6.2.1.jar:6.2.1]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:190) ~[spring-web-6.2.1.jar:6.2.1]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) ~[spring-webmvc-6.2.1.jar:6.2.1]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:986) ~[spring-webmvc-6.2.1.jar:6.2.1]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:891) ~[spring-webmvc-6.2.1.jar:6.2.1]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-6.2.1.jar:6.2.1]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1088) ~[spring-webmvc-6.2.1.jar:6.2.1]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:978) ~[spring-webmvc-6.2.1.jar:6.2.1]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) ~[spring-webmvc-6.2.1.jar:6.2.1]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) ~[spring-webmvc-6.2.1.jar:6.2.1]
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) ~[tomcat-embed-core-10.1.34.jar:6.0]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) ~[spring-webmvc-6.2.1.jar:6.2.1]
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) ~[tomcat-embed-core-10.1.34.jar:6.0]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) ~[tomcat-embed-websocket-10.1.34.jar:10.1.34]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-6.2.1.jar:6.2.1]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.2.1.jar:6.2.1]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-6.2.1.jar:6.2.1]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.2.1.jar:6.2.1]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-6.2.1.jar:6.2.1]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.2.1.jar:6.2.1]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at java.base/java.lang.Thread.run(Thread.java:1583) ~[na:na]

마찬 가지로 로그를 통해 AOP 어노테이션별 실행 순서를 확인할 수 있다.


#3-A -  localhost:8080/api/getPrivateInfo : request Header 에 특정한 값("pass") 가 있을 때

2025-01-17T17:06:15.997+09:00  INFO 1644 --- [study_aspectj] [nio-8080-exec-4] c.p.study_aspectj.sample.util.LogHelper  : AROUND AOP METHOD IS START
2025-01-17T17:06:15.997+09:00  INFO 1644 --- [study_aspectj] [nio-8080-exec-4] c.p.study_aspectj.sample.util.LogHelper  : AUTH-CHECK-AOP START
2025-01-17T17:06:15.997+09:00  INFO 1644 --- [study_aspectj] [nio-8080-exec-4] c.p.study_aspectj.sample.util.LogHelper  : BEFORE AOP METHOD IS RUNNING
2025-01-17T17:06:15.997+09:00  INFO 1644 --- [study_aspectj] [nio-8080-exec-4] c.p.study_aspectj.sample.util.LogHelper  : AFTER AOP METHOD IS RUNNING
2025-01-17T17:06:15.997+09:00  INFO 1644 --- [study_aspectj] [nio-8080-exec-4] c.p.study_aspectj.sample.util.LogHelper  : AUTH-CHECK-AOP END
2025-01-17T17:06:15.997+09:00  INFO 1644 --- [study_aspectj] [nio-8080-exec-4] c.p.study_aspectj.sample.util.LogHelper  : AROUND AOP METHOD IS END

 

 

#3-B -  localhost:8080/api/getPrivateInfo : request Header 에 특정한 값("pass") 가 없을 때

더보기

2025-01-17T17:07:17.366+09:00  INFO 1644 --- [study_aspectj] [nio-8080-exec-5] c.p.study_aspectj.sample.util.LogHelper  : AROUND AOP METHOD IS START
2025-01-17T17:07:17.367+09:00  INFO 1644 --- [study_aspectj] [nio-8080-exec-5] c.p.study_aspectj.sample.util.LogHelper  : AUTH-CHECK-AOP START
2025-01-17T17:07:17.367+09:00 ERROR 1644 --- [study_aspectj] [nio-8080-exec-5] c.p.study_aspectj.sample.util.LogHelper  : AUCH-CHECK0-AOP IS DETECTING : UNVALID AUTH
2025-01-17T17:07:17.368+09:00 ERROR 1644 --- [study_aspectj] [nio-8080-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.lang.RuntimeException: AUCH-CHECK0-AOP IS DETECTING : UNVALID AUTH] with root cause

java.lang.RuntimeException: AUCH-CHECK0-AOP IS DETECTING : UNVALID AUTH
at cohttp://m.proxy.study_aspectj.sample.util.LogHelper.authCheckAOP(LogHelper.java:107) ~[main/:na]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89) ~[spring-aop-6.2.1.jar:6.2.1]
at cohttp://m.proxy.study_aspectj.sample.util.LogHelper.around(LogHelper.java:69) ~[main/:na]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.2.1.jar:6.2.1]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727) ~[spring-aop-6.2.1.jar:6.2.1]
at cohttp://m.proxy.study_aspectj.sample.service.SampleServiceImpl$SpringCGLIB$0.getPrivateInfo(<generated>) ~[main/:na]
at cohttp://m.proxy.study_aspectj.sample.controller.SampleController.getPrivateInfo(SampleController.java:34) ~[main/:na]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:257) ~[spring-web-6.2.1.jar:6.2.1]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:190) ~[spring-web-6.2.1.jar:6.2.1]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) ~[spring-webmvc-6.2.1.jar:6.2.1]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:986) ~[spring-webmvc-6.2.1.jar:6.2.1]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:891) ~[spring-webmvc-6.2.1.jar:6.2.1]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-6.2.1.jar:6.2.1]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1088) ~[spring-webmvc-6.2.1.jar:6.2.1]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:978) ~[spring-webmvc-6.2.1.jar:6.2.1]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) ~[spring-webmvc-6.2.1.jar:6.2.1]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) ~[spring-webmvc-6.2.1.jar:6.2.1]
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) ~[tomcat-embed-core-10.1.34.jar:6.0]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) ~[spring-webmvc-6.2.1.jar:6.2.1]
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) ~[tomcat-embed-core-10.1.34.jar:6.0]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) ~[tomcat-embed-websocket-10.1.34.jar:10.1.34]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-6.2.1.jar:6.2.1]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.2.1.jar:6.2.1]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-6.2.1.jar:6.2.1]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.2.1.jar:6.2.1]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-6.2.1.jar:6.2.1]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.2.1.jar:6.2.1]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63) ~[tomcat-embed-core-10.1.34.jar:10.1.34]
at java.base/java.lang.Thread.run(Thread.java:1583) ~[na:na]