AOP를 사용하지 않고 시간을 측정하려면, 시간 측정 코드를 각각의 메서드에 직접 작성해야 합니다. 이는 중복된 코드를 발생시키고, 유지보수를 어렵게 만들 수 있습니다. 또한, 시간 측정 로직을 수정하거나 제거해야 할 때에도 모든 메서드를 수정해야 하므로 번거로운 작업이 필요합니다.
package hello.hellospring.service;
@Transactional
public class MemberService {
/** * 회원가입 */ public Long join(Member member) {
long start = System.currentTimeMillis();
try {
validateDuplicateMember(member); //중복 회원 검증
memberRepository.save(member);
return member.getId();
} finally {
long finish = System.currentTimeMillis();
long timeMs = finish - start; System.out.println("join " + timeMs + "ms");
}
}
/** * 전체 회원 조회
*/ 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");
}
}
}
AOP는 관점 지향 프로그래밍의 약어로, 애플리케이션에서의 횡단 관심사(cross-cutting concern)를 모듈화하는 프로그래밍 패러다임입니다. 횡단 관심사란, 여러 모듈 또는 객체들이 공통적으로 가져야 하는 기능이나 로직을 말합니다. 예를 들어, 로깅, 트랜잭션 관리, 보안 등이 횡단 관심사의 예입니다.
AOP는 주요한 개념으로 '어드바이스(Advice)', '포인트컷(Pointcut)', '언포인트컷(Until Pointcut)', '애스팩트(Aspect)'를 가지고 있습니다. 어드바이스는 횡단 관심사의 실제 동작을 정의하며, 포인트컷은 어드바이스가 적용될 지점을 선택하는 기준입니다. 언포인트컷은 포인트컷의 부정 조건으로, 포인트컷에 포함되지 않는 지점을 선택합니다. 애스팩트는 어드바이스와 포인트컷의 결합으로, 실제로 적용되는 AOP의 단위입니다.
package com.springboot.basic.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class TimeTraceAop {
@Around("execution(* com.springboot.basic..*(..))")
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");
}
}
}
AOP의 동작 방식은 주로 프록시 패턴(Proxy Pattern)을 사용하여 구현됩니다. 프록시 패턴은 원본 객체를 감싸고, 클라이언트가 원본 객체에 접근할 때 프록시가 중간에서 제어하여 필요한 작업을 수행하고, 원본 객체에게 위임하는 방식입니다.