본 게시물은 김영한님의 “스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술” 강의를 바탕으로 작성했습니다.
AOP
AOP가 필요한 상황
AOP가 필요한 상황
- 모든 메소드의 호출 시간을 측정하고 싶을 때
- 공통 관심 사항(cross-cutting concern) vs 핵심 관심 사항(core concern)
- 회원 가입 시간, 회원 조회 시간을 측정하고 싶을 때
이러한 상황에서 시간을 측정하는 로직을 아래 그림과 같이 각각 작성해야 합니다.

MemberService 회원 조회 시간 측정
...
@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");
}
}
...
}
스프링 통합 테스트 코드를 실행하면 **join()**의 소요 시간이 나옵니다. 스프링 서버를 실행하고 http://localhost:8080/members에 접속하면 **findMembers()**의 소요 시간이 나옵니다.


문제점
이런 식으로 다른 로직의 소요 시간을 측정하기 위해서도 각각 try~finally 코드를 작성해야 합니다. 1000개 중 2개를 해서 998개가 남았다고 생각하면 앞이 막막합니다. 이와 같이 과정에서 여러 문제점이 발생합니다.
- 회원가입, 회원 조회에 시간을 측정하는 기능은 핵심 관심 사항이 아님
- 시간을 측정하는 로직은 공통 관심 사항
- 시간을 측정하는 로직과 핵심 비즈니스의 로직이 섞여서 유지보수가 어려움
- 시간을 측정하는 로직을 별도의 공통 로직으로 만들기 매우 어려움
- 시간을 측정하는 로직을 변경할 때 모든 로직을 찾아가면서 변경해야 함
이러한 문제점을 해결하기 위해 AOP를 사용합니다.
AOP 적용
AOP란?
공통 관심 사항(cross-cutting concern)과 핵심 관심 사항(core concern)을 분리하는 Aspect Oriented Programming으로 관점 지향 프로그래밍입니다.

시간 측정 AOP 등록
시간 측정 AOP를 만들기 위해 aop 패키지와 TimeTraceAop 클래스를 만듭니다. 앞에 만들었던 MemberService의 시간 측정 로직은 모두 지워줍니다.
package hello.hello_spring.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(* hello.hello_spring..*(..))")
public Object excute(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를 @Component 애너테이션을 통해 스프링 빈으로 등록했는데 SpringConfig에서 직접 등록해도 무관합니다.
- @Around 애너테이션으로 적용 범위를 선택할 수 있습니다.
시간 측정 AOP 실행 및 결과

시간 측정 AOP 코드를 작성 후 실행하면 위 사진처럼 메소드마다 실행 시간을 알 수 있습니다.
AOP의 장점
- 회원가입, 조회 등 핵심 관심 사항과 시간을 측정하는 공통 관심 사항을 분리합니다.
- 시간을 측정하는 로직을 별도의 공통 로직으로 만들었습니다.
- 핵심 관심 사항을 깔끔하게 유지할 수 있습니다.
- 변경이 필요하면 이 로직만 변경하면 됩니다.
- 원하는 적용 대상을 선택할 수 있습니다.
스프링의 AOP 동작 방식
AOP 적용 전 의존관계

AOP 적용 후 의존관계

AOP를 memberService에 적용하면 스프링 빈으로 등록될 때 실제 객체 대신 프록시 객체가 스프링 컨테이너에 등록됩니다. 메서드가 호출되면 먼저 프록시 객체의 메서드가 실행되어 AOP 로직을 수행합니다. joinPoint.proceed() 메서드가 호출되면 프록시가 실제 객체의 메서드를 호출하여 비즈니스 로직이 수행됩니다.
이를 전체적으로 보면 아래 그림과 같습니다.
AOP 적용 전 전체 의존관계

AOP 적용 후 전체 의존관계

'Development > Spring' 카테고리의 다른 글
| [Spring] 스프링 입문 - 강의 정리 6 (0) | 2026.02.08 |
|---|---|
| [Spring] 스프링 입문 - 강의 정리 5 (0) | 2026.02.08 |
| [Spring] 스프링 입문 - 강의 정리 4 (0) | 2026.02.08 |
| [Spring] 스프링 입문 - 강의 정리 3 (0) | 2026.02.08 |
| [Spring] 스프링 입문 - 강의 정리 2 (0) | 2026.02.08 |