스프링 및 스프링 부트의 관점 지향 프로그래밍(aop) 자세히 알아보기

스프링 및 스프링 부트의 관점 지향 프로그래밍(aop) 자세히 알아보기

원문: Naveen Metta, "Deep Dive into Aspect-Oriented Programming (AOP) in Spring and Spring Boot"

서론

관점 지향 프로그래밍(AOP)은 애플리케이션의 횡단 관심사를 모듈화하는 강력한 패러다임입니다. 스프링과 스프링 부트는 AOP를 강력하게 지원하여 로깅, 보안, 트랜잭션과 같은 관심사를 핵심 애플리케이션 로직에서 분리하고 관리할 수 있게 해 줍니다. 이 글에서는 AOP의 기본 개념을 살펴보고 스프링과 스프링 부트에서 AOP를 어떻게 활용할 수 있는지 자세히 알아보겠습니다. 또한 각 개념을 명확하게 이해할 수 있도록 상세한 코드 예제와 설명도 함께 제공합니다.

관점 지향 프로그래밍(AOP)이란 무엇인가?

관점 지향 프로그래밍(AOP)은 소프트웨어 애플리케이션에서 횡단 관심사의 모듈화를 가능하게 하는 프로그래밍 패러다임입니다. 횡단 관심사는 코드베이스의 여러 부분에 영향을 미치는 애플리케이션의 측면입니다. 로깅, 보안, 트랜잭션, 오류 처리가 그 예시입니다. AOP는 이러한 관심사를 핵심 애플리케이션 로직에서 분리할 수 있게 하여 코드를 더 유지보수하기 쉽고 덜 복잡하게 만듭니다.

핵심 용어

스프링과 함께 AOP를 다루기 전에 몇 가지 주요 용어를 명확히 해 봅시다.

  • Aspect: Aspect는 횡단 관심사를 캡슐화하는 모듈입니다. 이는 Advice와 Pointcut을 포함합니다.

  • Advice: Advice는 특정 Pointcut과 일치할 때 실행되는 코드입니다. Advice에는 "before", "after", "around", "after-throwing"과 같은 여러 종류가 있습니다.

  • Pointcut: Pointcut은 코드베이스에서 Aspect의 Advice가 적용될 위치를 정의하는 표현입니다. 애플리케이션의 특정 Join Point를 선택합니다.

  • Join Point: Join Point는 프로그램 실행의 특정 지점입니다. 메서드 호출, 생성자 호출 또는 필드 접근 등이 있습니다.

AOP 개념

AOP는 여러 기본 개념을 도입합니다.

  • 횡단 관심사(Cross-Cutting Concerns): 로깅, 보안 또는 트랜잭션과 같이 애플리케이션의 여러 부분에 영향을 미치는 관심사입니다.

  • Aspects: Aspects는 횡단 관심사를 캡슐화하는 모듈입니다. 이는 Advice와 Pointcuts으로 구성됩니다.

  • Advice: Advice는 특정 Join Points에서 실행되는 코드입니다.

  • Pointcuts: Pointcuts는 Advice가 적용될 위치를 정의하는 표현입니다.

  • Join Points: Join Points는 Advice가 적용될 수 있는 애플리케이션 실행의 특정 지점입니다.

스프링 프로젝트 설정하기

기본 스프링 부트 프로젝트를 설정하는 것부터 시작합시다. 스프링 이니셜라이저(Spring Initializer)를 사용하여 필요한 의존성이 포함된 새 프로젝트를 만들 수 있습니다.

"스프링 웹"과 "스프링 AOP" 의존성을 포함하도록 합니다. 프로젝트가 생성되면 선호하는 IDE로 가져올 수 있습니다.

Aspects 생성하기

스프링에서는 @Aspect로 어노테이션이 달린 클래스를 정의하여 Aspect을 생성할 수 있습니다. 이 클래스는 advice 메서드를 포함해야 합니다.

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class LoggingAspect {

    @Before("execution(* com.example.demo.*.*(..))")
    public void logBefore() {
        System.out.println("Before method execution");
    }
}

이 예제에서 LoggingAspect 클래스는 com.example.demo 패키지의 모든 메서드 실행 전에 메시지를 로깅하는 @Before advice를 포함하고 있습니다.

Pointcuts 정의하기

Pointcut은 Advice가 적용될 위치를 정의합니다. Join Point를 지정하기 위해 표현식을 사용할 수 있습니다. 위 예제에서 "execution(* com.example.demo..(..))"은 지정된 패키지의 모든 메서드 실행을 선택합니다.

Pointcut 표현은 다음과 같은 몇 부분으로 구성됩니다.

  • execution: 이 키워드는 메서드 실행을 위한 Pointcut을 정의합니다.

  • *: 이 와일드카드는 모든 반환 유형에 일치합니다.

  • com.example.demo.*: 패키지와 클래스 이름을 지정합니다.

  • *.*(..): 모든 메서드 이름과 모든 인수에 일치합니다.

Pointcut 표현식은 특정 메서드와 클래스를 대상으로 하여 세부적으로 맞춤화할 수 있습니다.

Advices 작성하기

스프링은 다양한 유형의 Advice를 지원합니다.

  • @Before: Join Point 전에 실행됩니다.

  • @After: Join Point 후에 실행됩니다.

  • @Around: Join Point를 감싸 Join Point의 동작을 수정할 수 있습니다.

  • @AfterThrowing: Join Point에서 예외가 발생할 경우 실행됩니다.

예제의 @Before advice는 메서드가 실행되기 전에 메시지를 로깅합니다. Advice 유형에 대한 간단한 설명은 다음과 같습니다.

  • @Before Advice: 메서드 실행 전에 취할 행동을 위해 사용됩니다. 예를 들어 로깅, 보안 검사 또는 사전 처리에 사용할 수 있습니다.

  • @After Advice: 메서드 실행 후에 실행됩니다. 자원 정리 또는 최종 작업과 같은 작업에 유용합니다.

  • @Around Advice: 이는 가장 강력한 Advice 유형입니다. 메서드 주변을 감싸고 실행을 제어할 수 있습니다. 입력과 출력을 수정하고, 메서드 전후에 추가 행동을 수행하며, 메서드의 실행을 방지할 수도 있습니다.

  • @AfterThrowing Advice: 메서드 실행 중 예외가 발생할 때 실행됩니다. 이 Advice를 사용하여 예외를 처리하거나 로깅할 수 있습니다.

모두 결합하기

Aspect를 적용하려면 스프링 부트 애플리케이션에서 AOP를 활성화해야 합니다. 메인 애플리케이션 클래스에 @EnableAspectJAutoProxy 어노테이션을 추가합니다.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@SpringBootApplication
@EnableAspectJAutoProxy
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

이 어노테이션은 AspectJ 기반 프록시 생성을 활성화하고 스프링이 애플리케이션의 구성요소에 Aspect를 짜 넣을 수 있게 합니다.

AOP 구현 테스트하기

프로젝트에 샘플 서비스와 컨트롤러를 만들고 애플리케이션을 실행합니다. 지정된 패키지의 메서드 실행 전에 "Before method execution" 메시지가 출력되는 것을 확인할 수 있습니다.

이제 고급 AOP 기법을 탐구하고 스프링과 스프링 부트에서 AOP를 더 깊이 다루어 봅시다.

고급 AOP 기법

AOP는 애플리케이션의 모듈성과 유연성을 향상하기 위한 다양한 고급 기법을 제공합니다.

AspectJ와 사용자 정의 어노테이션

스프링 AOP는 프록시 기반의 AOP를 제공하는 반면, AspectJ는 더 강력하고 포괄적인 AOP 프레임워크를 제공합니다. AspectJ를 사용자 정의 어노테이션과 함께 사용하여 Aspect를 정의할 수 있습니다.

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Loggable {
}

@Aspect
public class CustomAspect {
    @Before("@annotation(Loggable)")
    public void logMethod(JoinPoint joinPoint) {
        // 로그 메서드 실행
    }
}

이 예제에서는 @Loggable 어노테이션을 사용하여 로깅해야 할 메서드를 표시합니다. @Before Advice는 @Loggable로 어노테이션이 달린 메서드의 실행을 로깅합니다.

AspectJ 표현식

AspectJ는 고급 Pointcut 표현식을 제공하여 타겟팅할 메서드와 클래스를 세밀하게 제어할 수 있습니다. 이러한 표현식은 클래스 계층 구조, 메서드 매개변수 등에 매칭할 수 있습니다.

@Around("execution(* com.example.service.*.*(..)) && args(arg1, arg2)")
public Object customAroundAdvice(ProceedingJoinPoint joinPoint, Object arg1, Object arg2) {
    // advice 로직을 커스텀합니다.
    return joinPoint.proceed();
}

이 예제에서는 Pointcut 표현식이 특정 인자를 갖는 com.example.service 패키지의 메서드와 매칭합니다.

Aspect 순서 지정하기

Aspect 내의 Advice 실행 순서를 설정하는 order 값을 설정함으로써 Advice 실행 순서를 제어할 수 있습니다. 낮은 값은 높은 값보다 먼저 실행됩니다.

@Aspect
public class OrderingAspect {

    @Before("execution(* com.example.service.*.*(..))")
    public void beforeAdvice() {
        // 이 advice는 다른 것보다 먼저 실행됩니다.
    }
}

기본적으로 같은 Aspect 내의 Advice는 순서가 0입니다. @Order 어노테이션을 사용하여 Aspect의 특정 순서를 설정할 수 있습니다.

AOP에서 예외 처리하기

AOP는 예외를 우아하게 처리할 수 있는 메커니즘을 제공합니다. 예를 들어 @AfterThrowing Advice를 사용하여 예외를 로깅하거나 처리할 수 있습니다.

@Aspect
public class ExceptionHandlingAspect {
    @AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "ex")
    public void handleException(Throwable ex) {
        // 예외를 처리합니다.
    }
}

이 Advice는 지정된 패키지의 메서드에서 발생한 예외를 포착하고 적절히 처리합니다.

스프링 부트에서의 AOP

앞서 살펴본 바와 같이 스프링 부트에서의 AOP 통합은 원활합니다. 스프링 부트의 자동 구성은 AOP 설정을 간소화하며 로깅, 보안, 모니터링 등 다양한 목적으로 AOP를 쉽게 활용할 수 있습니다.

결론

이 포괄적인 글에서는 스프링과 스프링 부트에서 관점 지향 프로그래밍(AOP)에 대해 깊이 파고들었습니다. AOP의 기본 개념, AOP가 있는 스프링 프로젝트 설정, Aspect 생성, Pointcut 정의 및 Advice 작성을 다루었습니다. 또한 AspectJ, 사용자 정의 어노테이션, 고급 Pointcut 표현, Aspect 순서 및 예외 처리와 같은 고급 AOP 기법을 살펴봤습니다.

AOP는 애플리케이션의 횡단 관심사를 관리하는 데 있어 강력한 도구입니다. 관심사를 효과적으로 모듈화 하고 코드베이스를 깔끔하고 유지보수하기 쉽게 유지함으로써, 더 강력하고 유지보수가 용이한 소프트웨어 시스템을 구축할 수 있습니다. 스프링과 스프링 부트의 AOP 지원을 통해 애플리케이션의 모듈성과 유연성을 향상할 수 있습니다.