티스토리 뷰

IT/Spring

Spring AOP 완전 정복 - 핵심 로직과 횡단 관심사의 완전 분리

Stv 2025. 6. 5. 17:57

목차


    1. AOP란 무엇인가?

    📌AOP의 정의

    AOP는 공통된 관심사를 분리하여 핵심 로직과 독립적으로 관리할 수 있도록 하는 프로그래밍 패러다임이다.

     

    🎯AOP가 필요한 이유

    OOP(Object-Priented Programming)만으로는 다음 같은 문제를 해결하기 어렵다.

    • 로킹, 트랜잭션, 보안 체크, 캐싱, 성능 측정 등은 모든 비즈니스 로직에 반복해서 들어감
    • 이러한 횡단 관심사(Cross-cutting concerns)가 중복 코드 유발 + 유지보수 난이도 증가

    ➡️ AOP는 이 관심사를 핵심 로직에서 분리해 재사용성과 응집도를 높임

     


    🧩 2. AOP 핵심 용어 정리

    용어 설명
    Aspect 횡단 관심사의 모듈화 단위 (클래스)
    Join Point Advice가 적용될 수 있는 지점 (ex: 메서드 실행)
    Advice Join Point에서 실행되는 코드 (Before, After 등)
    Pointcut Advice를 적용할 join Point의 패턴 정의
    Weaving Advice를 실제 코드에 적용하는 과정 (실행 전/후 삽입)

    3. Spring AOP 동작 구조

    📌Spring AOP의 핵심 원리 : 프록시 기반

    • Spring AOP는 JDK Dynamic Proxy 또는 CGLIB 또는 CGLIB Proxy를 사용하여 프록시 객체를 생성함
    • 클라이언트는 프록시를 호출하고, 프록시는 내부에서 실제 대상 메서드 + AOP 로직을 호출함 

    ⚙️ 동작 흐름

    [클라이언트]
        ↓
    [프록시 객체] ———> [Advice 실행] → [실제 비즈니스 메서드 호출] → [After Advice]

     

    🔍 AOP 적용 대상

    • 기본적으로 Spring Bean에만 적용
    • public 메서드만 Pointcut 대상 (Spring AOP는 Proxy 방식이라 제한 있음)

    4. Advice 유형별 실전 예제

    @Aspect
    @Component
    public class LoggingAspect {
    
        @Before("execution(* com.example.service..*(..))")
        public void logBefore(JoinPoint joinPoint) {
            System.out.println("Before: " + joinPoint.getSignature());
        }
    
        @AfterReturning(pointcut = "execution(* com.example.service..*(..))", returning = "result")
        public void logAfter(Object result) {
            System.out.println("AfterReturning: " + result);
        }
    
        @Around("execution(* com.example.service..*(..))")
        public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
            long start = System.currentTimeMillis();
            Object result = joinPoint.proceed();
            long end = System.currentTimeMillis();
            System.out.println("Execution Time: " + (end - start) + "ms");
            return result;
        }
    }

     

    예제 설명

    • @Before : 메서드 실행 전 로그 출력 
    • @AfterReturning : 메서드 정상 종료 후 반환값 로깅
    • @Around : 전체 흐름 감싸서 실행 시간 측정 

    🛠️ 5. 실무 적용 사례

    사례 AOP 적용 전 AOP 적용 후
    트랜잭션 처리 각 서비스마다 try-catch @Transactional
    로깅 모든 메서드에 System.out.println() @Before, @Around
    권한 체크 컨트롤러마다 isAdmin() 커스텀 어노테이션 + @Around

     

    ☑️ Custom Annotation 활용 예시

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface AdminOnly { }
    
    @Aspect
    @Component
    public class AuthAspect {
        @Before("@annotation(com.example.annotation.AdminOnly)")
        public void checkAdmin() {
            // 로그인 유저 권한 체크
        }
    }

    ⚠️ 6. 주의할 점 및 한계

    • private/protected 메서드에는 AOP 적용 불가
    • self-invocation 문제 : 자기 자신 호출에는 AOP 적용되지 않음
    • 프록시 기반이므로, 프록시를 우회하는 구조에서는 Advice가 작동하지 않음

    7. AOP와 SOLID의 관계

    SOLID 원칙 AOP 관련성
    SRP 핵심 로직과 공통 기능 분리로 단일 책임 실현
    OCP 공통 기능 확장 시 핵심 로직 건드리지 않음
    DIP 공통 기능을 별도 모듈로 분리하여 구현 의존성 제거
    DRY 중복 로직 제거 (로깅/트랜잭션 등)
    ISP 필요 시 특정 기능만 Interface로 모듈화 가능

    ✅ 마무리 요약

    • AOP는 로직 간의 관심사 분리를 통해 코드 품질을 높이는 강력한 도구
    • 실무에서는 @Transactional, @Async, @Cacheable 등이 모두 AOP의 대표 사례
    • AOP는 Spring의 프록시 기반으로 동작하며, 특정 한계가 존재하므로 이해가 필수