- aop : 메서드가 실행되기 전, 후의 여러 결과를 확인가능 => 로그를 남김
- 이걸 지원하지 않는 프레임워크라면 전,후 처리할 내용들을 각 메서드마다 넣어줘야하므로 비지니스 로직의 일관성을 해침
- 디버깅할 때 용이
(Rest컨트롤러)
@RestController
@RequestMapping("/api")
public class RestApiController {
@GetMapping("/get/{id}")
public String get(@PathVariable Long id, @RequestParam String name){
// System.out.println("===get method===");
// System.out.println("id: "+id);
// System.out.println("name: "+name); =>aop클래스에서 매개변수 로그를 찍어주므로 불필요
return id+" "+name;
}
@PostMapping("/post")
public User post(@RequestBody User user){
// System.out.println("===post method===");
// System.out.println(user);
return user;
}
@Timer
@DeleteMapping("/delete")
public void delete() throws InterruptedException {
Thread.sleep(1000*2);
}
@Decode
@PutMapping("/put")
public User put(@RequestBody User user){
System.out.println("put");
System.out.println(user);
return user;}}
1.
@Aspect //aop를 정의하는 클래스에 할당
@Component
public class ParameterAop {
@Pointcut("execution(* com.example.aop.controller..*.*(..))") //aop가 적용되는 지점설정(여기서는 컨트롤러 내 모든 메서드)
private void cut(){}
@Before("cut()") //cut()메소드 실행되기 이전 이 메소드를 사용하라는 의미
public void before(JoinPoint joinPoint) { //joinPoint: 들어가는 지점에 대한 정보를 가지고 있는 객체
MethodSignature methodSignature=(MethodSignature) joinPoint.getSignature(); //들어가는 지점의 메소드를 얻기 위한 작업
Method method=methodSignature.getMethod();
System.out.println(method.getName()); //메소드 이름
Object[] args = joinPoint.getArgs(); //지점의 매개변수들로 이루어진 배열(타입을 모르니 object로.. )
for (Object obj : args) {
System.out.println("type: "+obj.getClass().getSimpleName()); //즉, 타입명
System.out.println(obj);
}
}
@AfterReturning(value = "cut()",returning = "returnObj") //cut()이후에 값이 반환될 때 실행되고 그 반환값의 이름을 returnObj로 지정
public void after(JoinPoint joinPoint,Object returnObj){
System.out.println("return obj");
System.out.println(returnObj);
}
}
2. (어노테이션으로 영역표시)
@Target({ElementType.TYPE,ElementType.METHOD}) //Target: 이 어노테이션이 붙을 수 있는 애들 / TYPE: 클래스, 인터페이스
@Retention(RetentionPolicy.RUNTIME) //runtime때 사용한다는 의미
public @interface Timer {
//메소드 실행시간 => 서버의 부하/상태에 대한 로그를 남길 수 있음
@Aspect
@Component //클래스 단위로 bean을 등록 (cf. @Bean : 클래스에x, bean등록 메서드에만 씀 => @Configuration : 여러개의 bean이 등록되는 클래스에 붙임)
public class TimerAop {
@Pointcut("execution(* com.example.aop.controller..*.*(..))")
private void cut(){}
@Pointcut("@annotation(com.example.aop.annotation.Timer)") //aop지점=타이머 어노테이션이 있는 곳
private void enableTimer(){}
//특정 메서드의 실행시간을 알아보자
//그러려면 before 실행 부터 after실행 끝까지 걸린 시간을 재면 된다. => 시간을 공유해야하므로 before,after를 동시에 처리할 수 있는 around를 이용
@Around("cut()&&enableTimer()") //cut지점과 enableTimer지점을 동시에 만족하는 지점 => 즉, 컨트롤내에 timer어노테이션이 있는 지점
public void around(ProceedingJoinPoint joinPointer) throws Throwable {
//before 영역
StopWatch stopWatch=new StopWatch();
stopWatch.start();
//실행
Object result= joinPointer.proceed(); //메소드 실행!!! 실행되고 받은 리턴값도 받음(*메서드가 void형이면 암것도 안들어 감)
//after영역
stopWatch.stop();
System.out.println("total time: "+stopWatch.getTotalTimeSeconds());
}
}
3.
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Decode {
}
//base64로된 email 속성을 가진 요청을 put할 때 그걸 decode, encode하는 작업을 전후처리로 해보자
@Aspect
@Component
public class DecodeAop {
@Pointcut("execution(* com.example.aop.controller..*.*(..))")
private void cut(){}
@Pointcut("@annotation(com.example.aop.annotation.Decode)")
private void enableDecoder(){}
@Before("cut()&&enableDecoder()") //요청을 decode하여 객체에 넣어줌
public void before(JoinPoint joinPoint) throws UnsupportedEncodingException {
Object[] args=joinPoint.getArgs();
for(Object obj:args){
if(obj instanceof User){ //매개변수 객체가 user타입의 인스턴스이면 그걸 캐치하여
User user=User.class.cast(obj); // user로 캐스팅해준다.(Object->User)
String base64Email=user.getEmail();
String email=new String(Base64.getDecoder().decode(base64Email),"UTF-8");
user.setEmail(email);
}
}
}
@AfterReturning(value = "cut()&&enableDecoder()",returning = "returnObj")
public void afterReturning(JoinPoint joinPoint,Object returnObj){ //decode된 객체속성 가진 객체를 반환받는데, 이걸 다시 encode하여 응답으로 내보냄
User user=User.class.cast(returnObj);
String email=user.getEmail();
String base64Email=Base64.getEncoder().encodeToString(email.getBytes()); //encode할 땐 encode()가 아닌 encodeToString임에 주의
user.setEmail(base64Email);
}
}
'BackEnd > 패캠' 카테고리의 다른 글
Validation (0) | 2022.01.21 |
---|---|
AOP 실무 사례 알아보기 (0) | 2022.01.20 |
Ioc, DI (0) | 2022.01.18 |
모범사례 - Object Mapper (0) | 2022.01.17 |
Response 내려주기 및 모범사례 (0) | 2022.01.16 |
Comment