java/AOP
Spring AOP 구현
일상코더
2023. 3. 29. 15:04
AOP란?
AOP는 Aspect Oriented Programming의 약자로, 여러 객체에 공통으로 적용할 수 있는 기능을
분리해서 재새용성을 높여주 는 프로그래밍이다.
Spring에서는 주로 Logging, Caching, Auditing, Performace monitoring등에 주로 사용되며,
런타임 시에 프록시 객체를 생성하여 공통 기능을 삽입하는 방식으로 동작한다.
Spring AOP 구현하기
1. Application 혹은 Config파일에 @EnableAspectJAutoProxy 어노테이션 추가하기
@EnableAspectJAutoProxy
@SpringBootApplication
public class LogPracApplication {
public static void main(String[] args) {
SpringApplication.run(LogPracApplication.class, args);
}
}
2. Aspect 파일 만들기
package com.example.logprac.log;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;
@Aspect
@Component
public class LoggingAspect {
private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
// onRequest메서드에 Controller 패키지 내의 모든 파일에 대해 PointCut으로 정의하겠다는 설정
@Pointcut("within(com.example.logprac.controller..*)")
public void onRequest(){
}
// 위에서 PointCut으로 정의한 onRequest 파일들에 대해 @Around시점(메서드 호출 시점)에
// requestLogging 메서드를 실행하겠다는 내용
// Around: Around Advice를 줄여 @Around 어노테이션을 사용함
@Around("com.example.logprac.log.LoggingAspect.onRequest()")
public Object requestLogging(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
long start = System.currentTimeMillis();
try{
return proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
}finally {
long end = System.currentTimeMillis();
logger.info("Request: {} {}: {} ({}ms)", request.getMethod(), request.getRequestURL(), paramMapToString(request.getParameterMap()), end - start);
}
}
// 실제 객체(Controller의 메서드)를 호출하는 부분.
// 공통 로직에서 하고 싶은 행동은 proceed 전후에 정의한다.
private String paramMapToString(Map<String, String[]> paraStringMap){
return paraStringMap.entrySet().stream().map(entry -> String.format("%s : %s", entry.getKey(), Arrays.toString(entry.getValue()))).collect(Collectors.joining(", "));
}
}
AOP 주요 용어와 어노테이션
- Aspect: 여러 객체에 공통으로 적용되는 기능. 트랜젝션, 보안 등
- Advice: 언제 공통로직을 핵심 로직에 적용할지를 정의하는 것
- JoinPoint: Advice를 적용 가능한 지점으로, 스프링은 프록시를 이용하여 AOP를 구현하기
때문에 메서드 호출에 대한 JointPoint를 지원합니다.
- PointCut: JoinPoint의 부분 집합으로, 실제 Advice가 적용되는 JoinPoint를 나타낸다.