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를 다양한 방식으로 활용할 수 있었다.