이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.
- Target, Proxy, Aspect, Advice, Pointcut, Join point, Weaving은 한 호출 흐름에서 어떻게 연결되는가?
- 왜 Join point와 Pointcut을 구분해야 하는가?
- Spring AOP 용어를 외우는 대신 호출 흐름으로 이해하려면 어떤 순서로 봐야 하는가?
개요
Spring 공식 문서는 AOP 용어가 직관적이지 않지만 Spring만의 새 용어를 만들면 더 혼란스러워진다고 설명한다. 그래서 Spring AOP도 일반 AOP 용어를 사용한다. 공식 문서의 핵심 용어는 Aspect, Join point, Advice, Pointcut, Target object, AOP proxy, Weaving이다.
Spring AOP에서 Join point는 항상 Spring Bean의 메서드 실행을 의미한다. 또한 Spring AOP는 런타임 Proxy를 사용하므로 Target object와 AOP Proxy를 구분해서 이해해야 한다.
한 번에 보는 호출 흐름
클라이언트 코드
호출
Spring AOP Proxy
Pointcut 매칭
Advice 체인 실행
Target Bean 메서드 실행
반환 또는 예외
Advice 후처리
최종 결과 반환이 흐름에서 각 용어의 위치는 명확하다. Target은 실제 업무 메서드를 가진 객체다. Proxy는 Target 앞에 놓인 대리 객체다. Pointcut은 현재 호출이 Advice 대상인지 판단한다. Advice는 실행되는 부가 기능이다. Aspect는 Pointcut과 Advice를 묶은 모듈이다. Weaving은 이 전체 연결이 만들어지는 과정이다.
Target
Target은 핵심 비즈니스 로직을 가진 객체다. Spring AOP에서는 일반적으로 Spring Bean이 Target이 된다. 사용자는 보통 OrderService를 주입받는다고 생각하지만, AOP가 적용되면 실제 주입 객체는 OrderService 자체가 아니라 그 앞의 Proxy일 수 있다.
Target을 이해할 때 중요한 점은 “AOP가 적용될 대상”과 “호출자가 실제로 들고 있는 객체”가 다를 수 있다는 것이다. Target은 실제 일을 하는 객체이고, Proxy는 호출 경로를 가로채는 객체다.
Proxy
Proxy는 Target을 대신해서 호출을 먼저 받는 객체다. Spring AOP의 Proxy는 JDK Dynamic Proxy 또는 CGLIB Proxy로 만들어진다. Proxy는 자신이 받은 외부 호출을 바로 Target에 넘기지 않고, 해당 호출이 Pointcut에 맞는지 확인하고 필요한 Advice를 실행한다.
Proxy가 있기 때문에 원본 서비스 코드에 로그나 트랜잭션 코드를 직접 넣지 않아도 된다. 대신 Proxy가 호출 경계에서 공통 정책을 실행한다. 이 구조 때문에 Spring AOP는 Spring Container가 객체를 주입하는 순간에 강력하고, 직접 new로 만든 객체에는 자연스럽게 적용되지 않는다.
Aspect
Aspect는 횡단 관심사를 하나의 모듈로 묶은 것이다. 예를 들어 감사 로그 정책은 AuditAspect, 실행 시간 측정은 TimingAspect, 재시도 정책은 RetryAspect가 될 수 있다.
Aspect는 보통 다음 두 가지를 함께 가진다.
- 어디에 적용할지 나타내는 Pointcut
- 무엇을 실행할지 나타내는 Advice
@Aspect
@Component
public class AuditAspect {
@Pointcut("@annotation(com.example.Auditable)")
public void auditableOperation() {
}
@AfterReturning(pointcut = "auditableOperation()", returning = "result")
public void audit(JoinPoint joinPoint, Object result) {
log.info("audited method={}, result={}", joinPoint.getSignature(), result);
}
}Aspect를 “부가 기능 클래스”라고만 외우면 부족하다. Aspect는 정책의 모듈이다. 정책에는 적용 범위와 실행 행동이 함께 있어야 한다.
Advice
Advice는 특정 Join point에서 실제로 실행되는 코드다. Spring 문서에서는 Advice를 Interceptor 체인의 일부로 설명한다. 이 관점이 중요하다. 여러 Advice가 같은 메서드에 적용되면 하나의 호출 주변에 Advice 체인이 만들어진다.
Advice는 실행 시점에 따라 나뉜다.
@Before는 Target 메서드 전이다.@AfterReturning은 정상 반환 후다.@AfterThrowing은 예외 발생 후다.@After는 정상과 예외를 가리지 않는 종료 후다.@Around는 Target 호출 전후 전체를 감싼다.
Advice는 “코드 조각”이 아니라 “호출 시점에 대한 계약”이다. @Before는 반환값을 바꾸기 위한 자리가 아니고, @AfterThrowing은 정상 결과를 다루기 위한 자리가 아니다. 호출 여부, 인자, 반환값까지 바꿔야 할 때만 @Around를 검토한다.
Join point
Join point는 Advice가 적용될 수 있는 실행 지점이다. 일반 AOP에서는 메서드 실행, 생성자 호출, 필드 접근, 예외 처리 등 다양한 지점이 될 수 있다. 그러나 Spring AOP에서 Join point는 Spring Bean의 메서드 실행으로 제한된다.
이 제한은 단점이면서 장점이다. 필드 접근까지 다루지는 못하지만, Spring 애플리케이션에서 가장 중요한 실행 경계인 Bean 메서드 호출을 안정적으로 다룬다. 서비스 계층 트랜잭션, 캐싱, 메서드 보안, 모니터링은 대부분 이 수준에서 충분하다.
Pointcut
Pointcut은 Join point 후보 중 실제 Advice를 적용할 대상을 고르는 조건이다. “후보”와 “조건”을 분리해서 이해해야 한다.
예를 들어 모든 서비스 메서드 실행은 Join point 후보가 될 수 있다. 이 중 com.example.order..*Service 아래의 public 메서드만 고르는 조건이 Pointcut이다.
@Pointcut("execution(public * com.example..service..*(..))")
public void publicServiceOperation() {
}Pointcut은 단순 매칭 문자열이 아니다. 시스템의 실행 정책을 어떤 기준으로 적용할지 표현하는 설계 언어다. 패키지 기준으로 적용할지, 애너테이션 기준으로 적용할지, Bean 이름 기준으로 적용할지에 따라 시스템의 변경 비용이 달라진다.
Weaving
Weaving은 Aspect를 Target 실행 흐름에 연결하는 과정이다. Spring AOP는 런타임에 Proxy를 만들어 weaving을 수행한다. AspectJ는 컴파일 타임이나 로드 타임 weaving을 사용할 수 있으며, 이 경우 Spring AOP보다 더 넓은 Join point를 다룰 수 있다.
Spring AOP에서 weaving을 “Proxy 생성”으로 이해하면 많은 문제가 풀린다. Advice가 안 탄다면 먼저 이 질문을 던진다.
- 이 객체는 Spring Bean인가?
- 호출자가 Proxy를 통해 호출하는가?
- Pointcut이 실제 메서드 시그니처와 맞는가?
- 내부 호출로 Proxy를 우회하고 있지는 않은가?
용어를 연결해서 기억하는 방법
용어를 암기하지 말고 한 문장으로 연결한다.
클라이언트가 Proxy를 호출하면 Proxy는 Pointcut으로 현재 메서드 실행 Join point가 대상인지 판단하고, 대상이라면 Aspect 안의 Advice를 실행한 뒤 Target 메서드를 호출한다. 이 연결을 런타임에 Proxy로 만들어 내는 과정이 Spring AOP의 Weaving이다.
이 문장을 설명할 수 있으면 핵심 용어는 이미 연결된 것이다.
실전 팁
- “Aspect는 클래스, Advice는 메서드, Pointcut은 조건” 정도로만 외우면 디버깅이 어렵다. 항상 Proxy 호출 흐름에서 위치를 잡는다.
this와target은 Spring AOP에서 다르게 볼 수 있다.this는 Proxy 객체 기준이고target은 Proxy 뒤의 실제 Target 객체 기준이다.- 용어를 로그에 남길 때는
joinPoint.getSignature().toShortString()처럼 메서드 경계를 드러내는 정보를 사용한다. - Aspect가 많아지면 Advice 순서도 설계 대상이 된다. 관찰성 로그, 보안, 트랜잭션, 재시도 중 무엇이 바깥에서 감싸야 하는지 의식해야 한다.
- Pointcut 이름은 코드의 의도를 드러내야 한다.
pc1()보다serviceLayer()나auditableOperation()이 좋다.
확인 질문
확인 질문
- Aspect와 Advice의 차이는 무엇인가?
- Aspect는 횡단 관심사를 모은 모듈이고 Advice는 그 안에서 특정 시점에 실행되는 코드다.
- Join point와 Pointcut의 차이는 무엇인가?
- Join point는 Advice가 붙을 수 있는 후보 지점이고 Pointcut은 그 후보를 고르는 조건이다.
- Spring AOP에서 Weaving은 주로 무엇을 의미하는가?
- 런타임에 Proxy를 만들어 Aspect와 Target 호출 흐름을 연결하는 것이다.
- Target과 Proxy를 구분해야 하는 이유는 무엇인가?
- Advice는 Proxy를 통과하는 호출에 적용되므로 Target 내부 호출이나 직접 생성 객체에서는 동작하지 않을 수 있기 때문이다.