AOP

이재현·2024년 9월 12일

Spring

목록 보기
13/13

🤍 AOP

OOP: Object Oriented Programming
복잡한 프로그래밍 세상을 객체로 정의하는 목적이 있다.
AOP: Aspect Oriented Programming
복잡한 프로그래밍 세성에서 관심사를 분리하여 모듈로 사용하는데 목적이 있다.


🩵 AOP란?

AOP는 여러가지 소프트웨어 개발 패러다임 중 하나이다.
프로그램의 핵심 비즈니스 로직에서 횡단 관심사(cross-cutting concerns)를 분리하는 방법이다.

  • 횡단 관심사: 여러 모듈이나 컴포넌트에서 공통적으로 발생하는 로깅, 보안, 트랜잭션 관리와 같은 기능을 의미한다.

AOP를 사용하면 이러한 관심사를 핵심 비즈니스 로직과 분리하여 코드의 중복을 줄이고 가독성 및 유지보수성을 높일 수 있다.




🩵 AOP 주요 개념

  1. Aspect (애스펙트)
@Aspect
@Component
public class LoggingAspect {

    @Before("execution(* com.example.service.*.*(..))") 
    public void logMethodDetails(JoinPoint joinPoint) {
        System.out.println("Method: " + joinPoint.getSignature().getName());
        System.out.println("Arguments: " + Arrays.toString(joinPoint.getArgs()));
    }
}
  • Aspect는 횡단 관심사를 모듈화한 것으로, 횡단 관심사를 캡슐화한 클래스나 객체이다.
  • 예를 들어, 로깅 기능을 담당하는 로직이 Aspect로 구현될 수 있습니다.

  1. Join Point (조인 포인트)
@Aspect
@Component
public class LoggingAspect {

    @Before("execution(* com.example.service.*.*(..))") 
    public void logMethodDetails(JoinPoint joinPoint) {
        System.out.println("Method: " + joinPoint.getSignature().getName());
        System.out.println("Arguments: " + Arrays.toString(joinPoint.getArgs()));
    }
}
  • Join Point는 AOP에서 Aspect가 적용될 수 있는 지점이다.
  • 메서드 호출, 객체 생성, 예외 처리 등 다양한 지점이 될 수 있다.
  • Spring AOP에서는 주로 메서드 실행 시점이 Join Point로 사용된다.

  1. Advice (어드바이스)
@Aspect
@Component
public class LoggingAspect {

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

    @After("execution(* com.example.service.*.*(..))")
    public void afterAdvice() {
        System.out.println("After method execution");
    }

    @Around("execution(* com.example.service.*.*(..))")
    public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Before method execution (Around)");
        Object result = joinPoint.proceed();  // 실제 메서드 실행
        System.out.println("After method execution (Around)");
        return result;
    }

    @AfterThrowing("execution(* com.example.service.*.*(..))")
    public void afterThrowingAdvice() {
        System.out.println("Exception occurred");
    }
}
  • Advice는 Aspect가 특정 Join Point에서 수행하는 작업이다.
  • Advice는 코드 실행 전, 후, 또는 예외 발생 시에 실행될 수 있으며, 로깅, 트랜잭션 처리 등의 작업을 수행한다.
  • @Before: 메서드 실행 전에 실행.
  • @After: 메서드 실행 후에 실행.
  • @Around: 메서드 실행 전후에 모두 실행.
  • @AfterReturning: 메서드가 정상적으로 실행된 후에 실행.
  • @AfterThrowing: 메서드에서 예외가 발생한 경우 실행.

  1. Pointcut (포인트컷)
@Aspect
public class LoggingAspect {

    @Pointcut("execution(* com.example.service.UserService.*(..))") // UserService의 모든 메서드
    public void userServiceMethods() {}

    @Before("userServiceMethods()") // 위에서 정의한 포인트컷에 대해 Advice 적용
    public void logBeforeUserServiceMethods() {
        System.out.println("UserService method is about to be called");
    }
}
  • Pointcut은 Join Point를 선택하는 표현식이다.
  • Aspect가 적용될 지점을 명확하게 정의하기 위해 사용된다.
  • Spring AOP에서는 주로 메서드의 이름이나 패턴을 기준으로 Pointcut을 설정한다.
  1. Weaving (위빙)
  • Weaving은 Aspect와 핵심 비즈니스 로직을 엮는 과정이다.
  • 컴파일 시점, 로드 시점, 또는 런타임 시점에서 수행될 수 있다.
  • Spring AOP는 주로 런타임 위빙을 사용하여, 애플리케이션 실행 시에 Aspect를 한다.



🩵 Annotation을 이용한 AOP 방법

💙 Custom Annotation 생성

@Target(ElementType.METHOD) // 이 어노테이션을 메서드에만 사용할 수 있게 지정
@Retention(RetentionPolicy.RUNTIME) // 런타임에도 어노테이션 정보가 유지되도록 설정
public @interface LogExecutionTime {
}

💙 Aspect 클래스에서 어노테이션 처리

@Aspect
@Component
public class ExecutionTimeAspect {

    // @LogExecutionTime 애노테이션이 붙은 메서드에 대해 AOP 적용
    @Around("@annotation(LogExecutionTime)")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis(); // 메서드 실행 전 시간 측정

        Object proceed = joinPoint.proceed(); // 실제 메서드 실행

        long executionTime = System.currentTimeMillis() - start; // 메서드 실행 후 시간 계산

        System.out.println(joinPoint.getSignature() + " executed in " + executionTime + "ms");
        return proceed;
    }
}

@Aspect와 @Component를 사용하여 이 클래스가 Aspect 역할을 할 것임을 선언한다.
@Around("@annotation(LogExecutionTime)"): @LogExecutionTime 애노테이션이 붙은 모든 메서드에 대해 이 Aspect가 적용될 수 있다.
ProceedingJoinPoint를 사용하여 실제 메서드를 실행하고 그 실행 시간까지 측정한다.


💙 서비스 클래스에서 커스텀 어노테이션 사용

@Service
public class UserService {

    @LogExecutionTime
    public void createUser(String name) {
        // 사용자 생성 로직
        System.out.println("Creating user: " + name);
    }
    
    @LogExecutionTime
    public void deleteUser(String name) {
        // 사용자 삭제 로직
        System.out.println("Deleting user: " + name);
    }
}

@LogExecutionTime을 사용하여 createUser와 deleteUser 메서드에 AOP를 적용한다.
이 메서드가 실행될 때, ExecutionTimeAspect의 로직이 먼저 실행되어 실행 시간을 측정하고, 메서드가 종료된 후 측정된 시간을 출력한다.

0개의 댓글