개발/Spring

Spring AOP(Aspect-Oriented Programming) 가이드

피터JK 2025. 1. 29. 21:46
728x90

Spring AOP(Aspect-Oriented Programming)는 핵심 비즈니스 로직과 부가 기능(로깅, 트랜잭션, 보안 등)을 분리하여 유지보수를 쉽게 하는 기법입니다. Spring AOP의 핵심 개념과 예제를 정리하여, 실제 프로젝트에서 활용할 수 있도록 설명하겠습니다.


1. AOP란?

📍 AOP (Aspect-Oriented Programming)란?

  • OOP(Object-Oriented Programming)과 함께 사용되는 프로그래밍 기법
  • 핵심 비즈니스 로직을 횡단 관심사(Cross-Cutting Concerns)와 분리하여 코드의 가독성과 유지보수를 향상시킴.
  • 대표적인 횡단 관심사:
    • 로깅(logging)
    • 트랜잭션(transaction)
    • 보안(security)
    • 예외 처리(exception handling)

📍 AOP 적용 전후 비교

🔹 AOP 미적용 코드 (로깅이 포함된 서비스 메서드)

public class UserService {
    public void createUser(String username) {
        System.out.println("[LOG] 유저 생성: " + username);
        // 핵심 비즈니스 로직 실행
        System.out.println("사용자 생성 완료");
    }
}

🔹 문제점: 모든 서비스 로직에 로깅 코드가 포함되어 코드 중복 발생

🔹 AOP 적용 후 코드

@Aspect
@Component
public class LoggingAspect {
    @Before("execution(* com.example.service.*.*(..))")
    public void logBeforeMethod(JoinPoint joinPoint) {
        System.out.println("메서드 실행 전: " + joinPoint.getSignature().getName());
    }
}

🔹 AOP를 적용하면 핵심 로직과 부가 기능을 분리하여 유지보수성을 높일 수 있음


2. Spring AOP 주요 개념

📌 1. Aspect (에스팩트)

  • 횡단 관심사를 정의하는 모듈
  • 부가 기능을 모듈화하여 여러 곳에서 재사용 가능

📌 2. Advice (어드바이스)

  • 언제(시점)에 실행할지 정의하는 기능
  • 종류 :
    종류 Advice 종류 실행 시점
    @Before 메서드 실행
    @After 메서드 실행 (성공/실패 여부 관계없이)
    @AfterReturning 메서드가 정상적으로 실행된 후
    @AfterThrowing 예외 발생 시 실행
    @Around 메서드 실행 전후 모두 실행

📌 3. Advice 모든 예제 코드

@Aspect
@Component
public class LoggingAspect {
    
    @Before("execution(* com.example.service.*.*(..))")
    public void logBeforeMethod(JoinPoint joinPoint) {
        System.out.println("메서드 실행 전: " + joinPoint.getSignature().getName());
    }

    @After("execution(* com.example.service.*.*(..))")
    public void logAfterMethod(JoinPoint joinPoint) {
        System.out.println("메서드 실행 후: " + joinPoint.getSignature().getName());
    }

    @AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        System.out.println("메서드 실행 후 반환값: " + result);
    }

    @AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "exception")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable exception) {
        System.out.println("예외 발생: " + exception.getMessage());
    }

    @Around("execution(* com.example.service.*.*(..))")
    public Object logAroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("메서드 실행 전: " + joinPoint.getSignature().getName());
        Object result = joinPoint.proceed();
        System.out.println("메서드 실행 후: " + joinPoint.getSignature().getName());
        return result;
    }
}

3. 다양한 Pointcut 표현식

표현식 설명
execution(* com.example.service.*.*(..)) com.example.service 패키지의 모든 메서드 적용
within(com.example.service..*) 특정 패키지의 모든 클래스 적용
bean(userService) userService 빈에만 적용
args(String, int) 첫 번째 매개변수가 String, 두 번째가 int인 메서드에 적용
@annotation(org.springframework.transaction.annotation.Transactional) @Transactional이 붙은 메서드에 적용

AND(&&), OR(||), NOT(!) 연산자로 Pointcut 조합 가능

@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceMethods() {}

@Pointcut("@annotation(com.example.annotation.MyAnnotation)")
public void annotatedMethods() {}

@Before("serviceMethods() && annotatedMethods()")
public void logBefore(JoinPoint joinPoint) {
    System.out.println("특정 어노테이션이 있는 Service 메서드 실행 전");
}

4. 결론

개념 설명
Aspect 부가 기능(로깅, 트랜잭션 등)을 정의하는 모듈
Pointcut 어떤 메서드에 AOP 적용할지 결정하는 규칙
Advice 메서드 실행 전후에 실행되는 실제 기능
JoinPoint AOP가 적용될 수 있는 실행 지점 (메서드 호출 등)

🚀 Spring AOP를 사용하면 공통 기능을 모듈화하여 유지보수를 쉽게 할 수 있음!

 

728x90