- 객체 지향 프로그래밍 패러다임을 보완하는 기술로 메소드나 객체의 기능을 핵심 관심사(Core Concern)와 공통 관심사(Cross-cutting Concern)로 나누어 프로그래밍하는 것을 말합니다.“핵심 관심사”는 각 객체가 가져야 할 본래의 기능이며, “공통 관심사”는 여러 객체에서 공통적으로 사용되는 코드를 말합니다.
- 여러 개의 클래스에서 반복해서 사용하는 코드가 있다면 해당 코드를 모듈화 하여 공통 관심사로 분리합니다. 이렇게 분리한 공통 관심사를 Aspect로 정의하고 Aspect를 적용할 메소드나 클래스에 Advice를 적용하여 공통 관심사와 핵심 관심사를 분리할 수 있습니다. 이렇게 AOP에서는 공통 관심사를 별도의 모듈로 분리하여 관리하며, 이를 통해 코드의 재사용성과 유지 보수성을 높일 수 있습니다.
[참고] 프로그래밍 패러다임과 관련하여 작성한 글 : https://adjh54.tistory.com/97
💡 관점 지향 프로그래밍의 정의를 보면 핵심 관심사와 공통 관심사를 분리하여 프로그래밍하는 것을 의미합니다.
💡 여기서 3개의 A, B, C의 클래스가 있다고 가정합니다.
클래스 A에서는 주황, 파랑, 빨간색 블록으로 구성이 되어 있고 클래스 B에서는 빨강, 주황 블록으로 구성되어 있으며 클래스 C에서는 주황, 파랑 블록으로 구성되어 있습니다. 해당 색은 클래스 A, B, C에서 동일하게 사용되는 코드를 의미합니다.
예를 들어서 클래스 A에서 주황색 블록을 수정을 하게 되면 클래스 B, C에서도 수정을 해야 합니다. 이렇게 되면 유지보수 차원에서 모든 코드를 수정해야 하니 불편한 점이 있습니다. 그래서 Aspect X에서는 공통 관심사인 주황색 블록을 묶어서 모듈화를 시켜서 코드의 재 사용성과 유지 보수성을 강화하였습니다.
이렇듯, 관점 지향 프로그래밍에서는 소스코드에서 반복적으로 사용하는 코드를 하나로 묶어서 모듈화하여 재사용성과 유지 보수성을 높일 수 있는 강점을 가지고 있습니다.
💡 해당 코드는 프로젝트 패키지에서 Controller 패키지 내에서 메서드가 수행되기 전, 후, 실행되어 반환된 후, 예외가 발생하였을 때에 해당 메서드가 수행되도록 처리가 되었습니다.
💡 그렇기에 Controller 패키지 내에서 매번 호출이 되었는지에 대한 로깅을 작성했던 부분에 대해서 로깅을 줄일 수 있는 이점이 생겼습니다.
package com.adjh.multiflexapi.aspects;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* 로깅 관련 AOP 구성
*
* @author : jonghoon
* @fileName : LoggingAspect
* @since : 2023/03/01
*/@Aspect@Component@Slf4jpublicclassLoggingAspect {
/**
* Before: 대상 “메서드”가 실행되기 전에 Advice를 실행합니다.
*
* @param joinPoint
*/@Before("execution(* com.adjh.multiflexapi.controller.*.*(..))")publicvoidlogBefore(JoinPoint joinPoint) {
log.info("Before: " + joinPoint.getSignature().getName());
}
/**
* After : 대상 “메서드”가 실행된 후에 Advice를 실행합니다.
*
* @param joinPoint
*/@After("execution(* com.adjh.multiflexapi.controller.*.*(..))")publicvoidlogAfter(JoinPoint joinPoint) {
log.info("After: " + joinPoint.getSignature().getName());
}
/**
* AfterReturning: 대상 “메서드”가 정상적으로 실행되고 반환된 후에 Advice를 실행합니다.
*
* @param joinPoint
* @param result
*/@AfterReturning(pointcut = "execution(* com.adjh.multiflexapi.controller.*.*(..))", returning = "result")publicvoidlogAfterReturning(JoinPoint joinPoint, Object result) {
log.info("AfterReturning: " + joinPoint.getSignature().getName() + " result: " + result);
}
/**
* AfterThrowing: 대상 “메서드에서 예외가 발생”했을 때 Advice를 실행합니다.
*
* @param joinPoint
* @param e
*/@AfterThrowing(pointcut = "execution(* com.adjh.multiflexapi.controller.*.*(..))", throwing = "e")publicvoidlogAfterThrowing(JoinPoint joinPoint, Throwable e) {
log.info("AfterThrowing: " + joinPoint.getSignature().getName() + " exception: " + e.getMessage());
}
/**
* Around : 대상 “메서드” 실행 전, 후 또는 예외 발생 시에 Advice를 실행합니다.
*
* @param joinPoint
* @return
* @throws Throwable
*/@Around("execution(* com.adjh.multiflexapi.controller.*.*(..))")public Object logAround(ProceedingJoinPoint joinPoint)throws Throwable {
log.info("Around before: " + joinPoint.getSignature().getName());
Objectresult= joinPoint.proceed();
log.info("Around after: " + joinPoint.getSignature().getName());
return result;
}
}
[ 더 알아보기 ]
💡 @EnableAspectJAutoProxy 어노테이션 - 스프링 컨텍스트 내에서 AspectJ AOP 프레임워크를 사용할 수 있도록 하는 어노테이션입니다.해당 어노테이션을 사용하면 AOP 프록시 빈을 자동으로 등록하고 AOP를 사용할 수 있게 됩니다. Spring Boot에서는 @EnableAspectJAutoProxy 어노테이션을 사용하지 않아도 AspectJ AOP 프레임워크를 사용할 수 있습니다. 이는 Spring Boot가 자동으로 AOP 프록시 빈을 등록하고 AOP를 사용할 수 있게 해 주기 때문입니다.
1. Controller로 호출이 되는 사용자 리스트를 조회하는 API 호출을 수행하였습니다.
2. 서버의 콘솔을 확인합니다.
💡 해당 콘솔을 확인하면 총 4번의 구성한 LogginAspect.java 부분에 로깅이 출력되었습니다.
1. @Around: Around before로 메서드가 실행되기 전에 수행되는 부분이 출력되었습니다. 2. @Before: Before로 메서드가 실행되기 전에 수행되는 부분이 출력되었습니다. 3. @AfterReturning: AfterReturning로 메서드가 정상적으로 수행된 뒤에 메서드 명과 결과값이 출력이 되었습니다. 4. @After: After로 메서드가 실행된 후에 결과값이 출력되었습니다.