순서
AOP를 Spring Boot에서 실행하기 위해 다음의 단계들을 거칩니다.
- 의존성 추가
- Application에 Annotation 추가
- Aspect 파일 생성
- 메소드 생성
- 실행 범위 지정
- 실행 코드 구현
의존성 추가
implementation 'org.springframework.boot:spring-boot-starter-aop'
Application에 Annotation 추가
@EnableAspectJAutoProxy 이 어노테이션을 어플리케이션 클래스에 추가합니다.
@SpringBootApplication
@EnableAspectJAutoProxy // aop 사용
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
}
파일 생성
저 같은 경우는 aop 패키지를 생성하고 LoggingAspect.java 클래스 파일을 생성해 작업을 했습니다.
- @Aspect, @Component, @Slf4j 어노테이션 추가
- AOP 메소드 생성
전체 코드
package com.dotd.user.aop;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Aspect
@Component
@Slf4j
public class LoggingAspect {
// Before : 메소드 실행 전
@Before("execution(* com.dotd.user.controller..*(..))")
public void logBefore(JoinPoint joinPoint) {
log.info("Before 실행 : {}", joinPoint.getSignature().toShortString() );
}
// After : 메소드 실행 후
@After("execution(* com.dotd.user.controller..*(..))")
public void logAfter(JoinPoint joinPoint) {
log.info("After 실행 : {}", joinPoint.getSignature().toShortString() );
}
// AfterReturning : 메소드가 실행하고 반환된 후 실행
// returning 은 결과값을 받을 객체를 선택
@AfterReturning(value = "execution(* com.dotd.user.controller..*(..))", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
log.info("AfterReturning 실행 : {} + 결과 : {}", joinPoint.getSignature().toShortString(), result);
}
// AfterThrowing : 메소드에 예외가 발생했을 때 실행
// throwing 은 예외값을 받을 객체를 선택
@AfterThrowing(pointcut = "execution(* com.dotd.user.controller..*(..))", throwing = "e")
public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
log.info("AfterThrowing 실행 : {} + 예외 : {}", joinPoint.getSignature().toShortString(), e);
}
// Around : 실행 전, 후
@Around("execution(* com.dotd.user.controller..*(..))")
public Object logAroundControllerMethods(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
log.info("Around 시작 : {}", joinPoint.getSignature().toShortString());
// 실제 메서드 실행
// 이 코드를 기준으로 전, 후가 나누어짐
Object result = joinPoint.proceed();
long elapsedTime = System.currentTimeMillis() - startTime;
log.info("Around 끝 : {} / 걸린 시간 : {} ms", joinPoint.getSignature().toShortString(), elapsedTime);
return result;
}
}
메소드
@Before("execution(* com.dotd.user.controller..*(..))")
public void logBefore(JoinPoint joinPoint) {
log.info("Before 실행 : {}", joinPoint.getSignature().toShortString() );
}
메소드의 각각 요소들에 대해 알아보겠습니다.
@Before("execution(* com.dotd.user.controller..*(..))")
- @Before : @뒤에 AOP메소드의 실행 지점을 설정합니다. (After, AfterReturning, Around .. )
- "execution(* com.dotd.user.controller..*(..))" 은 AOP를 적용할 대상을 뜻 합니다.
- 여기서는 com.dotd.user.controller 의 패키지와 하위 패키지에 적용합니다.
public void logBefore(JoinPoint joinPoint) {
log.info("Before 실행 : {}", joinPoint.getSignature().toShortString() );
}
- JoinPoint joinPoint 은 프로그램 실행 중에 특정 위치를 말합니다. 즉, Advice(AOP의 코드)를 삽입할 수 있는 프로그램의 특정 지점을 의미합니다.
- joinPoint.getSignature().toShortString() : join point에 대해 짧은 문자열로 반환
실행 시점
Around 전 -> Before -> 로직 -> AfterReturning -> After -> Around 후
이 순서로 실행되는 것을 볼 수 있습니다.