Spring/Spring 공부

4. AOP 코딩 실습-2

개발자잡 2022. 7. 2. 15:35

AOP+ Custom annotation을 만들어서 특정 메서드의 실행 시간 측정하기.

 

 

컨트롤러에서는 서비스에 대한 로직만 남겨두고

나머지 반복되는 로직은 AOP에서 작성하는 것이 좋다.

또한 사용할 어노테이션을 만들고 사용하는 것도 가능하다.

 

사용할 어노테이션 : @Around

 

package com.example.aop.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Timer {
}
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.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

@Aspect
@Component
public class TimerAop {

    @Pointcut("execution(* com.example.aop.controller..*.*(..))")
    private void cut(){}

    @Pointcut("@annotation(com.example.aop.annotation.Timer)")
    //패키지 하위 타이머 어노테이션 메소드에 로깅한다.
    private void enableTimer(){}

    @Around("cut() && enableTimer()")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        Object result = joinPoint.proceed();

        stopWatch.stop();
        System.out.println("total time : "+stopWatch.getTotalTimeSeconds());
        //이러한 메소드들이 얼마나 걸렸는지 시간을 측정해줌.
    }



}
@Timer
    @DeleteMapping("/delete")
    public void delete() throws InterruptedException {

        //db logic 1sec ~2sec

        Thread.sleep(1000*2);
    }

}

TIMER 어노테이션을 생성하고 @Around를 사용하여 반복 적인 기능을 AOP에 작성하여 시간을 측정하였다.

 

암호화되거나 AOP구간에서 변환해주거나 특정한 규칙을 넣어줄 수 있다.

들어올 떄 복호화하거나 나갈 떄 암호화 하는 것을 AOP구간에서 변환할 수 있다.

 

package com.example.aop.annotation;

public @interface Decode {
}

 

@Aspect
@Component
public class DecodeAop {

    @Pointcut("execution(* com.example.aop.controller..*.*(..))")
    private void cut(){
    }

    @Pointcut("@annotation(com.example.aop.annotation.Decode)")
    private void enableDecode(){}

    @Before("cut() && enableDecode()")
    public void before(JoinPoint joinPoint) throws UnsupportedEncodingException {
        //특정 객체에 관한 특전 변수를 설정
        Object[] args = joinPoint.getArgs();

        for(Object arg : args){
            if(arg instanceof User){
                User user = User.class.cast(arg);
                String base64Email = user.getEmail();
                String email = new String(Base64.getDecoder().decode(base64Email), "UTF-8");
                user.setEmail(email);
            }//메서드 파라미터 중 원하는 user라는 클래스가 매칭이 되면 user 클래스로 형변환. 기존에는 인코딩 되어 있던 이메일을 꺼내고
        }//디코딩을 시켜 set을 시켜준다.

    }

    @AfterReturning(value = "cut() && enableDecode()", returning = "returnObj")
    public void afterReturn(JoinPoint joinPoint, Object returnObj){
        if(returnObj instanceof User){
            User user = User.class.cast(returnObj);
            String email = user.getEmail();
            String base64email = Base64.getEncoder().encodeToString(email.getBytes());
            user.setEmail(base64email);
        }

    }
}

디코드에 대한 AOP를 설정.

@Decode
@PutMapping("/put")
public User put(@RequestBody User user){
    System.out.println("put");
    System.out.println(user);
    return user;
}
System.out.println(Base64.getEncoder().encodeToString("steve@gmail.com".getBytes()));

이메일을 base64로 인코딩을 하고 c3RldmVAZ21haWwuY29t 라는 값을 얻었다.

 

이 값을 PUT으로 전송해 보았다.

정상적으로 RETURN 된 것을 확인 할 수 있었다.

 

AOP를 다양한 방식으로 활용할 수 있었다.