yata project에서는 실행 결과가 나오는 모든 시점

controller/service코드의 실행 전/후에 로그를 남기도록 구현하였다.

 

 

LogAspect Class 전체코드

@Aspect //이 클래스가 Aspect클래스임을 명시
@Slf4j
@Profile("local")
@Component //스프링 빈으로 등록
public class LogAspect {

    @Pointcut("execution(* com.yata.backend..*(..))")
    public void all() {
    }
    @Pointcut("execution(* com.yata.backend..*Controller.*(..))")
    public void controller() {
    }
    @Pointcut("execution(* com.yata.backend..*Service.*(..))")
    public void service(){}
    @Around("all()")
    public Object logging(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        try {
            Object result = joinPoint.proceed();
            return result;
        } finally {
            long finish = System.currentTimeMillis();
            long timeMs = finish - start;
            log.info("log = {}" , joinPoint.getSignature());
            log.info("timeMs = {}", timeMs);
        }
    }
    //특정 조인포인트에서 수행될 부가기능을 정리
    @Before("controller() || service()")
    public void beforeLogic(JoinPoint joinPoint) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        log.info("method = {}", method.getName());

        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
            if(arg != null) {
                log.info("type = {}", arg.getClass().getSimpleName());
                log.info("value = {}", arg);
            }

        }
    }
    @After("controller() || service()")
    public void afterLogic(JoinPoint joinPoint) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        log.info("method = {}", method.getName());

        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
            if(arg != null) {
                log.info("type = {}", arg.getClass().getSimpleName());
                log.info("value = {}", arg);
            }

        }
    }



}

 

📌pointcut

유지보수와 확장성을 위해 pointcut을 메서드로 만들어 사용해주었다

사용한 pointcut 메서드는 총 3개이다

1. com.yata.backend 패키지의 하위 패키지에 있는 모든 메서드를 대상으로 설정하는 pointcut

2. com.yata.backend 패키지의 하위 패키지에 있는 모든 Controller를 대상으로 설정하는 pointcut

3. com.yata.backend 패키지의 하위 패키지에 있는 모든 Service를 대상으로 설정하는 pointcut

 

📌Advice 정의

 

특정 조인포인트(Join Point)에서 수행될 부가기능을 정리

@Around("pointcut")에너테이션 사용

=> 메서드 호출 전/후/예외발생 시점에 실행

 

all()메서드로 정의한 포인트컷을 넣어줌

 

파라미터에는 proceedingJoinPoint 사용

🔎JoinPoint
JoinPoint 인터페이스는 호출되는 대상 객체, 메서드, 전달 파라미터 목록에 접근 할 수 있는 메소드 제공

메서드 접근하는 영역
Signature getSignature() 호출되는 메서드에 대한 정보
Object getTarget() 대상 객체
Object[] getArgs() 파라미터 목록

org.aspectj.lang.Signature인터페이스는 호출되는 메서드와 관련된 정보를 제공
메서드 접근하는 영역
String getName() 메서드 이름
String toLongName() 메서드를 완전하게 표현한 문장(반환 타입, 파라미터 타입)
String getArgs() 파라미터 목록

구현 시 주의 사항
JoinPoint를 파라미터로 전달 받을 경우 반드시 첫번째 파라미터로 지정해야한다 (그 회, 예외 발생)

🔎ProceedingJoinPoint
JoinPoint를 상속받은 객체(JoinPoint와Signature메서드를 이용할 수 있음)
ProceedingJoinPoint는 Around advice(@Around)에서만 지원되는 JoinPoint
Around Advice는 ProceedingJointPoint를 첫 번째 파라미터로 전달받음
Target Object의 메소드 정보를 포함(ProceedingJoinPoint.proceed()는 Target의 메소드 실행을 제어할 수 있음)

System.currentTimeMillis() => 현재 시간(메서드 실행 시작 시각) 측정

 

joinPoint.proceed() -> Advice가 적용된 메서드 실행 수 결과 반환, 결과 result에 저장

 

finally블록 -> 위 메서드 실행이 완료된 후 실행되는 코드(Advice이후 추가 로직 수행)

 

System.currentTimeMillis() -> 메서드 실행 완료 시각 측정

 

timeMs => 메서드 실행에 걸린 시간 계산

 

log.info() 메서드 시그니처, 메서드 실행 시간 출력

=> joinPoint.getSignature() => 현재 Advice가 적용된 메서드의 시그니처(메서드명, 매개변수 등)을 가져

    result => Advice 이후 메서드 실행 결과

@Before("pointcut")에너테이션 사용

컨트롤러와, 서비스 코드 시작 전에 실행할 부가기능

 

methodSignature에서 getMethod()를 통해 메서드에 대한 정보를 가져옴

실행될 메서드의 이름을 로그로 남김

 

실행하는 메서드의 파라미터의 타입과 값들을 하나씩 로그로 남김

 

 

@After("pointcut")에너테이션 사용

컨트롤러와 서비스 코드 실행 후 수행될 부가기능

 

methodSignature에서 getMethod()를 통해 메서드에 대한 정보를 가져옴

실행된 메서드의 이름을 로그로 남김

 

메서드의 파라미터의 타입과 값을 각각 로그로 남김

 

 

 

메서드의 수행 시간과

이제 메서드 호출 전/후 전달된 인자값을 쉽게 확인할 수 있게 되었다.

 

 

복사했습니다!