관점지향 프로그램
스프링 어플리케이션은 대부분 특별한 경우를 제외하고는 보통 MVC 웹 어플리케이션 WebLayer,Buisness Layer, Data Layer로 정의된다.
우선 AOP를 적용하기 위해 컨트롤러를 만들어준다. 그 전에 controller 패키지 폴더를 만드는 것을 잊으면 안된다.
@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("get "+ id);
System.out.println("get method " + name);
return id + " " + name
}
@PostMapping("/post")
public User post(@RequestBody User user){
System.out.println("post method: "+user);
return user;
}
}
그리고 aop패키지를 만들고 ParameterAop 클래스를 만들어준다.
@Aspect
@Component // Spring으로써 컴포넌트로 관리를 해주기 위해 컴포넌트 어노테이션 추가
public class ParameterAop {
// 특정 패키지 하위(controller 하위)
@Pointcut("execution(* com.ioc.ioc.controller..*.*(..))")
private void cut(){}
// 위에 메소드
@Before("cut()")
public void before(JoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
for(Object obj: args){
System.out.println("type"+obj.getClass().getSimpleName());
System.out.println("value"+obj);
}
}
@AfterReturning(value = "cut()",returning = "obj")
public void afterReturning(JoinPoint joinPoint,Object obj){
System.out.println("return object");
System.out.println(obj);
}
}
스프링 Run후 api가 호출될때마다 전 후 출력이 되는 것을 확인할 수 있다.
public class ParameterAop {
...
// 위에 메소드
@Before("cut()")
public void before(JoinPoint joinPoint){
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
System.out.println(method.getName());
}
}
어노테이션을 이용해서 메서드들을 전체 걸린 시간을 출력하는 AOP를 만들어보겠다.
일단 annotation 패키지를 만들고 Target annotaion을 생성해준다.
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME) // 런타임 실행시
public @interface Timer { }
aop 패키지 하위에 TimerAop 클래스를 만들어준다.
@Aspect
@Component // Aop 클래스는 bean으로 등록할 수 없고 메소드에 bean을 붙일 수 있다.
public class TimerAop {
// 특정 패키지 하위(controller 하위)
@Pointcut("execution(* com.ioc.ioc.controller..*.*(..))")
private void cut(){}
@Pointcut("@annotation(com.ioc.ioc.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());
}
}
그리고 예시를 돕기 위해서 Controller API메서드를 하나 추가해준다.
@RestController
@RequestMapping("/api")
public class RestApiController {
...
@Timer
@DeleteMapping("/delete")
public void delete() throws InterruptedException{
Thread.sleep(1000 * 2); // 2초간 슬립
}
}
실행 후 delete 메서드를 api를 통해 call해주면 total time 2.000086563
시간이 잘 뜨게된다!