이와 같이 패키지 전체를 포인트 컷으로 잡아서 구현한 AOP를 Custom AOP로 바꾸어보았습니다.
@Aspect
@Component
public class LogAspect {
private static final Loggerlogger= LoggerFactory.getLogger(LogAspect.class);
@Around("within(com.myproject.doseoro..*)")
public Object logging(ProceedingJoinPoint pjp) throws Throwable {
String params = getRequestParams();
long startAt = System.currentTimeMillis();
logger.info("----------> REQUEST : {}({}) = {}", pjp.getSignature().getDeclaringTypeName(),
pjp.getSignature().getName(), params);
Object result = pjp.proceed();
long endAt = System.currentTimeMillis();
logger.info("----------> RESPONSE : {}({}) = {} ({}ms)", pjp.getSignature().getDeclaringTypeName(),
pjp.getSignature().getName(), result, endAt-startAt);
return result;
}
private String getRequestParams() {
String params = "";
RequestAttributes requestAttribute = RequestContextHolder.getRequestAttributes();
if (requestAttribute != null) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
.getRequestAttributes()).getRequest();
Map<String, String[]> paramMap = request.getParameterMap();
if (!paramMap.isEmpty()) {
params = " [" + paramMapToString(paramMap) + "]";
}
}
return params;
}
private String paramMapToString(Map<String, String[]> paramMap) {
StringJoiner sj = new StringJoiner(",", "[", "]");
return paramMap.entrySet().stream()
.map(entry -> String.format("$s -> ($s)",
entry.getKey(), sj,join(entry.getValue())))
.collect(Collectors.joining(", "));
}
}
바꾼 이유는 공부 목적도 있었고 멘토님이 말하시길 "코드상 눈에 보이는 표식을 하지 않았기 때문에 모르는 사람이 볼때는 Aspect 로직이 왜 실행되는지 이해를 하지 못하는 경우도 많다"고 하셨다. 듣고 보니 정말 그럴 것 같았다.
어떻게 바뀌었냐면
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Logging {}
@Aspect
@Component
public class LogAspect {
private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);
@Around("@annotation(Logging)") // Custom AOP
public Object logging(ProceedingJoinPoint pjp) throws Throwable {
// ... 이하 위 로직과 같음
이렇게 바꿈으로써 전에 없었던 어노테이션이 생겼고, 그 어노테이션으로 무엇을 하려고 하는지 정확히 알 수 있었습니다.
이 과정에서 @Transactional, @Cacheable, @Async 에너테이션도 AOP가 적용된 사례라는 것을 알게되었습니다.
참고
https://velog.io/@ann0905/AOP%EC%99%80-Transactional%EC%9D%98-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC
AOP와 @Transactional의 동작 원리
오늘은 @Transactional의 동작 원리를 AOP와 함께 좀 더 자세하게 조사해보려고 한다.여기서 다루는 내용은 다음과 같다.AOP란 무엇이며 왜 사용하는가Spring AOP는 왜 프록시를 사용하는가@Transactional은
velog.io
https://tecoble.techcourse.co.kr/post/2021-06-25-aop-transaction/
AOP 입문자를 위한 개념 이해하기
이 글은 AOP 개념이 생소한 입문자들을 위한 포스팅입니다. 1. OOP의 한계 image…
tecoble.techcourse.co.kr
https://private-space.tistory.com/98
Spring에서 AOP를 구현하는 방법과 Transactional
Spring에서 AOP를 구현하는 방법과 Transactional AOP에 관한 간략한 개념이 필요하다면 다른 글을 참조한다. 이 내용은 공식 문서를 참조하여 작성하였다. Spring Framework Document AOP 구현 방식 Spring에서 A..
private-space.tistory.com
'난중(개발)일기 > 깨달음' 카테고리의 다른 글
Rest API에 대한 깨달음 (0) | 2023.01.07 |
---|---|
Hexagonal architecture로 구조를 바꿔보며.. (0) | 2022.10.04 |
PK에 seq(sequence)와 id에 대한 고찰 (0) | 2022.09.25 |
Mybatis 로 데이터 조회 후 객체에 저장할 때 기본생성자와의 연관관계 (1) | 2022.09.21 |
[MyBatis] MySql JSON 타입 MyBatis select로 가져오기 (0) | 2022.09.17 |