Topic (오늘의 주제)
Spring AOP (Aspect-Oriented Programming, 관점 지향 프로그래밍)
애플리케이션 전반에 걸쳐 흩어져 있는 부가 기능(로깅, 트랜잭션, 권한 처리 등)을 핵심 비즈니스 로직과 분리하여, 코드의 응집도를 높이고 유지보수성을 극대화하는 방법을 학습합니다.
Why (왜 사용하는가? 왜 중요한가?)
- 실무: 모든 비즈니스 메서드마다 DB 트랜잭션 시작/커밋 코드나 API 호출 시간을 측정하는 로깅 코드를 반복해서 작성하면, 정작 중요한 핵심 비즈니스 로직이 파묻히고 향후 수정이 발생했을 때 수백 개의 파일을 고쳐야 하는 악몽이 펼쳐집니다.
- 구조적 의미: 여러 모듈에 공통적으로 나타나는 횡단 관심사(Cross-cutting Concerns)를 독립적인 모듈(Aspect)로 분리해 냅니다. 이는 객체 지향 프로그래밍(OOP)의 단일 책임 원칙(SRP)을 더욱 완벽하게 지킬 수 있도록 돕는 구조적 보완재 역할을 합니다.
- 면접 의도: 지원자가 IoC/DI, Spring Bean 등 프레임워크의 기초를 넘어 프록시(Proxy) 디자인 패턴의 동작 원리를 이해하고 있는지, 그리고 @Transactional 같은 마법 같은 어노테이션이 내부적으로 어떻게 작동하는지(추상화된 기술의 내부 원리)를 확인하려 합니다.
Core Concept (핵심 개념 정리)
| 요소 | 내용 |
| 개념 정의 | 핵심 비즈니스 로직(Core Concern)과 공통 부가 기능(Cross-cutting Concern)을 분리하여 모듈화하는 프로그래밍 패러다임입니다. |
| 동작 방식 | Spring AOP는 런타임 프록시(Proxy) 방식을 사용합니다. Spring 컨테이너가 Bean을 생성할 때, 원본 객체(Target)를 감싸는 가짜 객체(Proxy)를 만듭니다. 클라이언트가 메서드를 호출하면 프록시가 먼저 요청을 가로채어 부가 기능(Advice)을 실행하고, 그 다음 실제 객체의 메서드를 호출합니다. |
| 장점/단점 | 장점: 코드 중복이 획기적으로 줄어들고, 개발자는 비즈니스 로직 구현에만 온전히 집중할 수 있습니다. 단점: 프록시를 거치는 오버헤드가 미세하게 존재하며, 프록시 기반이라는 구조적 특징 때문에 발생하는 '내부 호출(Self-invocation)'의 한계점을 명확히 알아야 합니다. |
| 필요 조건 | AOP를 적용할 객체는 반드시 Spring Bean으로 등록되어 있어야 합니다. 또한, 어디에(Pointcut) 어떤 기능(Advice)을 적용할지 정의한 모듈(Aspect) 구성이 필요합니다. |
| 예시/비교 | OOP vs AOP: AOP는 OOP를 대체하는 것이 아닙니다. OOP가 비즈니스 로직을 클래스 단위로 모듈화한다면, AOP는 클래스들을 가로지르는 '인프라 로직'을 모듈화하여 OOP를 더욱 객체지향적으로 만들어주는 파트너입니다. |
Interview Answer Version (면접 답변식 요약)
"AOP는 핵심 비즈니스 로직과 시스템 전반에 걸친 횡단 관심사(로깅, 보안, 트랜잭션 등)를 분리하여 모듈화하는 기법입니다.
이를 통해 코드의 중복을 줄이고 비즈니스 로직의 가독성과 유지보수성을 크게 높일 수 있습니다. Spring에서는 주로 디자인 패턴 중 하나인 프록시(Proxy) 패턴을 활용한 런타임 위빙 방식으로 AOP를 구현합니다.
가장 대표적인 활용 사례가 @Transactional 어노테이션이며, 개발자는 복잡한 트랜잭션 관리 코드를 직접 작성하지 않아도 Spring이 프록시를 통해 런타임에 자동으로 처리해 줍니다."
Practical Tip (사용시 주의할 점 or 활용 예)
- 실무 활용 예:
- 성능 측정: @LogExecutionTime 같은 커스텀 어노테이션을 만들고, @Around Advice를 사용해 컨트롤러나 서비스 메서드의 실행 시간을 밀리초 단위로 측정하여 병목 구간을 탐지할 때 유용하게 쓰입니다.
- 글로벌 예외 처리 및 로깅: API 호출 시 발생하는 요청/응답 데이터를 남기거나 에러 발생 시 특정 로그 서버로 데이터를 전송할 때 사용됩니다.
- 설정 시 반드시 고려해야 할 AOP 용어:
- Aspect: 흩어진 부가 기능(Advice) + 어디에 적용할지(Pointcut)를 합친 모듈 (클래스 레벨)
- Advice: 실질적으로 수행해야 하는 부가 기능 구현체 (메서드 레벨, @Before, @After, @Around 등)
- Pointcut: 어느 타겟의 어느 메서드에 Advice를 적용할지 필터링하는 표현식
- "이걸 모르고 사용하면 생기는 문제" (Self-invocation 문제 - 매우 중요):
- Spring AOP는 프록시 기반으로 동작합니다. 따라서 클라이언트가 외부에서 빈(Bean)의 메서드를 호출할 때는 프록시를 거치지만, 같은 클래스 내부에 있는 다른 메서드를 직접 호출할 때(this.메서드명())는 프록시를 거치지 않고 실제 객체 내부에서 돌아버립니다. * 즉, 같은 서비스 클래스 안에서 일반 메서드가 @Transactional이 붙은 다른 메서드를 내부 호출하면, 트랜잭션이 전혀 적용되지 않아 심각한 데이터 정합성 문제(롤백 실패)가 발생할 수 있습니다. 이를 해결하기 위해 자기 자신을 의존성 주입받거나, 구조를 분리하는 방식을 취해야 합니다.
예상 꼬리질문 정리
- Spring AOP가 프록시를 생성하는 두 가지 방식인 JDK Dynamic Proxy와 CGLIB의 차이점은 무엇인가요? Spring Boot에서는 기본적으로 어떤 방식을 채택하고 있나요?
- (의도: 인터페이스 기반 프록시와 클래스 상속 기반 프록시의 차이를 이해하고, 최신 Spring Boot의 디폴트 동작 원리를 아는지 확인)
- 방금 말씀하신 '내부 호출(Self-invocation)' 문제로 인해 @Transactional이 동작하지 않을 때, 실무에서는 이를 어떻게 해결하는 것이 가장 바람직한 구조적 접근일까요?
- (의도: AOP의 한계를 정확히 인지하고 있는지, 그리고 클래스/책임 분리(Refactoring)를 통해 문제를 우아하게 해결할 수 있는지 확인)
- 웹 요청 처리 과정에서 공통 로직을 처리할 수 있는 방법으로 Filter, Interceptor, 그리고 AOP가 있습니다. 이 세 가지의 차이점은 무엇이고, JWT 토큰 검증 로직은 셋 중 어디에 구현하는 것이 적절할까요?
- (의도: Spring MVC의 요청 생명주기(Request Lifecycle)를 이해하고, 목적에 맞게 적절한 계층을 선택하는 아키텍처 설계 능력을 확인)
'Archive > Daily Dev Q&A' 카테고리의 다른 글
| Daily Dev Q&A: Redis의 특징 (0) | 2026.02.24 |
|---|---|
| Daily Dev Q&A: 자바 리플렉션 (0) | 2026.02.23 |
| Daily Dev Q&A: 트랜잭션 격리 수준 (0) | 2026.02.02 |
| Daily Dev Q&A: 데이터베이스 락 (0) | 2026.02.02 |
| Daily Dev Q&A: 데이터베이스 동시성 이슈 (0) | 2026.01.29 |