어노테이션 먼저 정리
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]
'API' 카테고리의 다른 글
스프링 스케줄러와 배치 #1 - Spring Scheduler(@Scheduled), TaskScheduler (0) | 2025.03.09 |
---|---|
#2 TEST CODE 작성 : Todo API 단위테스트, 통합테스트 (0) | 2025.01.02 |
#1 TEST CODE 작성 : Todo API 만들기 (1) | 2024.12.14 |
[spring webSocket - 스프링 웹소켓] : 간이 채팅방 구현 (4) | 2024.09.16 |
WebSocketHandler - 오버라이드 메소드, override method 정리 (0) | 2024.09.16 |