Spring

Spring AOP에 대해서 설명해주세요

횡단 관심사 분리부터 프록시 메커니즘, Pointcut 표현식, Self-Invocation 함정까지. 면접에서 자주 묻는 Spring AOP의 핵심 개념을 인터랙티브 시각화로 완벽히 준비합니다.

2026년 3월 15일 · 약 15분 읽기

Q. "Spring AOP가 무엇인지 설명하고, 내부적으로 어떤 방식으로 동작하는지 말씀해주세요."

예상 꼬리질문

답변 가이드

"Spring AOP는 횡단 관심사(Cross-Cutting Concerns)를 비즈니스 로직과 분리하는 프레임워크입니다. 로깅, 트랜잭션, 보안처럼 여러 모듈에 반복되는 코드를 Aspect로 모아 한 곳에서 관리합니다."

"내부적으로 런타임 프록시 기반으로 동작합니다. 인터페이스가 있으면 JDK Dynamic Proxy, 없으면 CGLIB 프록시를 생성해 원본 객체를 감싸고, Pointcut에 매칭된 메서드 호출 시 Advice를 실행합니다."

"가장 흔한 함정은 Self-Invocation입니다. 같은 클래스 내부에서 메서드를 호출하면 프록시를 거치지 않아 @Transactional 같은 AOP가 동작하지 않습니다. 해결책은 기능을 별도 Service로 분리하는 것입니다."

@Transactional 어노테이션 하나로 트랜잭션이 자동으로 관리되는 이유가 궁금했나요? Spring AOP가 없었다면 모든 Service 메서드에 try-catch-rollback 코드를 반복해야 했을 겁니다.

이 아티클에서는 면접의 꼬리질문 흐름을 따라가며, AOP가 해결하는 문제부터 프록시 동작 원리, Self-Invocation 함정까지 직접 만져볼 수 있는 시각화로 체험합니다.


1. AOP가 해결하는 문제 — 횡단 관심사의 중복

꼬리질문: "AOP가 해결하려는 횡단 관심사가 무엇인지 설명해주세요"

모든 API 호출을 로깅하려면 어떻게 해야 할까요? AOP 없이는 Controller 메서드마다 로그 코드를 반복해야 합니다. 100개 메서드라면 100번 복사-붙여넣기입니다.

횡단 관심사(Cross-Cutting Concerns)는 여러 모듈에 걸쳐 반복되는 공통 기능입니다. Spring AOP는 이를 Aspect로 분리해 한 곳에서 선언하면 자동으로 적용되게 합니다.

Spring의 @Transactional, @Cacheable, @Async는 모두 내부적으로 AOP를 사용합니다.

AOP 적용 전후 코드 구조를 비교해보세요.

❌ AOP 없음
UserService
log.info("메서드 실행");
tx.begin();
// 비즈니스 로직
catch (e) {tx.rollback();}
OrderService
log.info("메서드 실행");
tx.begin();
// 비즈니스 로직
catch (e) {tx.rollback();}
ProductService
log.info("메서드 실행");
tx.begin();
// 비즈니스 로직
catch (e) {tx.rollback();}
중복 코드 9회 반복
✅ AOP 사용
@LoggingAspect
@Around
@Pointcut("execution(* com.example.service.*.*(..))")
3개 서비스 자동 적용
@TransactionAspect
@Around
@Pointcut("@annotation(Transactional)")
3개 서비스 자동 적용
→ 1회 선언으로 중복 제거

2. 핵심 용어 — Aspect, Pointcut, Advice, Join Point

꼬리질문: "Aspect, Pointcut, Advice, Join Point의 차이를 설명해주세요"

Aspect는 횡단 관심사를 모듈화한 클래스입니다. Pointcut은 Advice를 적용할 메서드를 선택하는 표현식이고, Advice는 실제 실행되는 코드로 실행 시점에 따라 @Before, @After, @Around 등 5가지 유형이 있습니다.

Join Point는 Advice가 적용될 수 있는 지점입니다. Spring AOP에서는 메서드 실행 시점만 지원합니다(AspectJ는 필드 접근, 생성자까지 지원).

각 용어가 실제 코드에서 어떻게 연결되는지 확인해 보세요.

카드를 클릭하여 핵심 용어를 탐색하세요

3. Advice 유형 5가지 — 언제 무엇이 실행되나

꼬리질문: "@Before, @After, @Around의 실행 순서와 차이를 설명해주세요"

@Before는 메서드 실행 전, @AfterReturning은 정상 완료 후, @AfterThrowing은 예외 발생 후, @After는 성공·실패 무관 항상 실행됩니다.

@Around는 실행 전후를 모두 제어하며 가장 강력합니다. ProceedingJoinPoint.proceed()를 호출하지 않으면 대상 메서드가 실행되지 않으니 주의하세요.

메서드 호출 타임라인에서 각 Advice가 언제 실행되는지 확인해 보세요.

@Around 시작
Object result = null;
@Before
logBefore(joinPoint);
메서드 실행
result = proceed();
@AfterReturning
logSuccess(result);
@After
cleanup();
@Around 종료
return result;
시나리오를 선택하고 자동 재생 또는 단계별로 진행하세요

4. Pointcut 표현식 — 어떤 메서드에 적용할지 선택하기

꼬리질문: "execution 표현식의 문법을 설명해주세요"

가장 많이 쓰는 execution은 메서드 시그니처로 매칭합니다. 패턴은 execution(접근제어자? 반환타입 패키지.클래스.메서드(파라미터))입니다.

@annotation은 특정 어노테이션이 붙은 메서드만 선택하며, 커스텀 어노테이션과 함께 쓰면 AOP를 선언적으로 제어할 수 있습니다.

표현식을 직접 작성하며 어떤 메서드에 매칭되는지 확인해 보세요.

표현식 빌더

생성된 표현식

execution(* com.example.service.*.*(..))

매칭 결과

0

매칭되는 메서드가 없습니다

5. 프록시 동작 원리 — JDK Dynamic Proxy vs CGLIB

꼬리질문: "Spring AOP가 프록시 기반으로 동작하는 원리를 설명해주세요"

Spring AOP는 런타임에 프록시 객체를 생성해 원본 객체를 감쌉니다. 클라이언트는 프록시를 호출하고, 프록시가 Advice를 실행한 뒤 원본 메서드를 호출합니다.

JDK Dynamic Proxy는 인터페이스를 구현한 경우 사용하며, CGLIB은 인터페이스가 없는 경우 대상 클래스를 상속받는 서브클래스를 생성합니다. Spring Boot 2.0+에서는 CGLIB이 기본값입니다.

CGLIB는 final 클래스나 final 메서드는 상속할 수 없으므로 프록시를 생성할 수 없습니다.

두 프록시 방식을 전환하며 동작 차이를 비교해 보세요.

JDK Dynamic Proxy
UserService (인터페이스)
↓ 구현
UserServiceProxy
↓ 위임
UserServiceImpl (실제 로직)

사용 조건

인터페이스가 있을 때

장점

가벼움, Java 표준 API

단점

인터페이스 필수

자동 재생 또는 단계별로 호출 흐름을 확인하세요

6. Self-Invocation 문제 — AOP의 가장 흔한 함정

꼬리질문: "Self-Invocation 문제가 무엇이고 어떻게 해결하나요?"

Spring AOP의 가장 흔한 버그는 Self-Invocation입니다. 같은 클래스 내에서 메서드를 this.method()로 직접 호출하면 프록시를 거치지 않아 AOP가 동작하지 않습니다.

@Transactional public void createUser()에서 this.sendEmail()을 호출하면 sendEmail의 @Transactional은 무시됩니다. 해결책은 (1) 기능을 별도 Service로 분리(권장), (2) 자기 자신을 @Autowired로 주입받아 프록시 경유 호출, (3) AopContext.currentProxy() 사용(비권장)입니다.

self-invocation이 발생하는 상황과 해결책을 직접 확인해 보세요.

잘못된 방식 (this 직접 호출)
ClientUserServiceProxycreateUser() 호출
UserServiceProxycreateUser프록시 통과
createUserthis.sendEmailthis 직접 호출
this.sendEmailsendEmail@Transactional 무시
결과: @Transactional 동작하지 않음
올바른 방식 (별도 Service 분리)
ClientUserServiceProxycreateUser() 호출
UserServiceProxycreateUser프록시 통과
createUseremailService다른 빈 호출
emailServiceEmailServiceProxy프록시 통과
EmailServiceProxysendEmail@Transactional 동작
결과: @Transactional 정상 동작

해결책 요약

Self-Injection
간단
단점: 순환 의존 가능
별도 Service 분리
권장 패턴
AopContext
가능
단점: 복잡, 비권장
실행 버튼을 눌러 두 흐름을 동시에 비교해보세요

7. Spring AOP vs AspectJ — 언제 무엇을 선택할까

꼬리질문: "Spring AOP와 AspectJ의 차이를 설명해주세요"

Spring AOP는 런타임 프록시 기반으로 간단하지만, 메서드 실행만 지원하고 프록시 오버헤드가 있습니다. AspectJ는 컴파일/로드 타임 위빙으로 바이트코드를 직접 조작하기 때문에 8~35배 빠르고, 메서드·필드·생성자 모든 Join Point를 지원하며 final·private도 가능합니다.

단, AspectJ는 별도 컴파일러(ajc)나 Java Agent가 필요해 복잡합니다. 일반 엔터프라이즈 애플리케이션에서는 Spring AOP로 충분합니다.

두 방식의 특성을 비교해 보세요.

비교 항목Spring AOPAspectJ
위빙 시점
런타임 프록시
컴파일/로드 타임
Join Point
메서드만⚠️
메서드·필드·생성자
성능
프록시 오버헤드
8~35배 빠름
복잡도
간단권장
복잡
final 지원
불가
가능
self-invocation
문제 발생
문제 없음
사용 시나리오
일반 엔터프라이즈 앱권장
고성능·세밀한 제어
각 셀에 마우스를 올려 상세 설명을 확인하세요

8. 실무 활용 사례 — 커스텀 어노테이션으로 선언적 AOP

꼬리질문: "AOP를 실무에서 어떻게 활용하는지 예시를 들어주세요"

실무에서는 @Loggable, @Timed, @RequireRole 같은 커스텀 어노테이션을 만들고, Aspect가 이 어노테이션을 감지해 동작하게 하는 패턴을 많이 씁니다.

예를 들어 @Retry(maxAttempts=3)를 메서드에 붙이면, Aspect가 실패 시 자동으로 재시도합니다. 비즈니스 로직은 어노테이션만 선언하면 되고, 부가 기능은 Aspect에서 중앙 관리됩니다.

커스텀 어노테이션 기반 AOP 동작을 직접 체험해 보세요.


면접 체크리스트

이 항목들을 자신 있게 설명할 수 있다면 Spring AOP 질문은 준비 완료입니다.

  • - AOP 개념: 횡단 관심사를 Aspect로 분리 — @Transactional, @Cacheable 모두 AOP 기반
  • - 핵심 용어: Aspect(모듈), Pointcut(선택 표현식), Advice(실행 코드), Join Point(적용 지점)
  • - 프록시 메커니즘: JDK Proxy(인터페이스) vs CGLIB(상속), Spring Boot 기본은 CGLIB
  • - Advice 5가지: @Before, @After, @AfterReturning, @AfterThrowing, @Around
  • - Self-Invocation 함정: 같은 클래스 내부 호출은 프록시를 거치지 않음 — 별도 Service 분리 권장
  • - AspectJ 비교: 컴파일 타임 위빙으로 더 빠르고 강력 — 일반 앱은 Spring AOP로 충분

참고 자료


의견을 들려주세요

서비스 개선에 큰 도움이 됩니다. 익명으로 자유롭게 남겨주세요.

0 / 1000
이전@ComponentScan 동작 원리 (준비 중)
다음JDK Dynamic Proxy vs CGLIB (준비 중)