회원 조회를 예를 들어보자.
아래의 코드를 보면 서비스단에서 회원 리포지토리를 통해 전체 회원의 목록을 가져온다.
public List<Member> findMembers() {
return memberRepository.findAll();
}
만약 이 메서드의 런타임을 알고싶다면 Aop를 모르는 우리는 어떻게 해야할까?
아래와 코드와 같이 System.currentTimeMillis() 메서드를 통해 시작과 종료시의 차를 이용해 처리된 시간을 구할 수 있다.
public List<Member> findMembers() {
long start = System.currentTimeMillis();
try {
return memberRepository.findAll();
} finally {
long finish = System.currentTimeMillis();
long timeMs = finish - start;
System.out.println("findMembers " + timeMs + "ms");
}
}
만약 여기서 시간을 확인해야하는 메서드가 1000개가 되면 유지보수 작업은 커녕 실 개발시에 소요되는 시간도 엄청날 것이다.
이때 AOP를 적용하면 쉽게 처리할 수 있다.
@Component
@Aspect
public class TimeTraceAop {
//AOP를 적용시킬 패키지 경로를 입력한다.
@Around("execution(* com.shlee..*(..))")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
System.out.println("START: " + joinPoint.toString());
try {
return joinPoint.proceed();
} finally {
long finish = System.currentTimeMillis();
long timeMs = finish - start;
System.out.println("END: " + joinPoint.toString()+ " " + timeMs + "ms");
}
}
}
@Component 어노테이션을 통해 스프링컨테이너에 빈등록을 해준다.
@Aspect 어노테이션을 사용하면 비즈니스 로직 실행 전, 후에 동작하게 된다.
@Around 어노테이션을 통해 AOP가 동작할 패키지를 지정한다. (위의 코드는 모든 메서드에서 동작하게 되어있다.)
작동방식을 짚고 넘어가자면
AOP를 사용하지 않을때 컨트롤러에서 서비스의 의존성을 주입받아 호출된다.
@Aspect 어노테이션을 사용하고 AOP를 서비스단 에만 적용하게 되면 서비스 프록시를 생성하게 되고, 컨트롤러에 주입된다.
이를 통해 실제 동작시 위에 정의한 excute 메서드가 서비스 시작, 종료 시간 및 런타임을 측정할 수 있다.