1. AOP란?
AOP(Aspect-Oriented Programming, 관점 지향 프로그래밍)는 비즈니스 로직과 공통 기능을 분리하여 중복 코드를 줄이고 유지보수성을 높이는 프로그래밍 패러다임이다
AOP의 핵심 개념
- 관점(Aspect): 비즈니스 로직과 관계없이 여러 곳에서 공통적으로 적용되는 기능 (예: 로깅, 트랜잭션 관리 등)
- 핵심 로직(Core Concern): 애플리케이션의 주요 비즈니스 로직
- 공통 관심 사항(Cross-Cutting Concern): 여러 클래스에서 반복적으로 나타나는 부가 기능
AOP의 역할
AOP는 비즈니스 로직의 특정 시점을 가로채어 전후 처리를 가능하게 해주는 기술
- 비즈니스 로직과 공통 기능을 분리하여 코드 중복을 줄임
- 애플리케이션의 가독성과 유지보수성을 향상
AOP의 주요 활용 사례
- 로깅 (Logging): 메서드 실행 전후의 로그 기록
- 트랜잭션 관리 (Transaction Management): 트랜잭션 자동 처리
- 예외 처리 (Exception Handling): 공통적인 예외 로깅 및 예외 변환
- 보안(Security): 접근 권한 제어
2. AOP 주요 개념과 용어
Advice | 언제 공통 기능을 핵심 기능에 적용할지 정의 |
JoinPoint | Advice를 적용 가능한 지점 (예: 메서드 호출, 필드 값 변경) |
Pointcut | JoinPoint의 부분집합 (특정 조건을 만족하는 JoinPoint) |
Weaving | Advice를 핵심 로직 코드에 적용하는 과정 |
Target Object | 하나 이상의 Aspect에 의해 Advice가 적용되는 객체 |
Aspect | 여러 객체에 공통으로 적용되는 공통 관심 사항을 정의하는 모듈 |
3. Spring AOP 적용 방식
1) @Aspect 사용 (Spring AOP 기본 제공 방식)
Spring은 @Aspect를 활용하여 AOP를 적용할 수 있음
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("메서드 실행 전: " + joinPoint.getSignature().getName());
}
}
- @Aspect: 이 클래스가 AOP 기능을 담당하는 Aspect임을 선언
- @Component: Spring이 관리하는 Bean으로 등록
- @Before: 메서드 실행 전에 수행될 Advice 설정
2) Spring AOP 적용 과정
- @EnableAspectJAutoProxy를 설정하면 Spring이 AOP 기능을 활성화
- @Aspect를 선언한 클래스에서 Advice와 Pointcut을 정의
- Spring이 자동으로 Weaving하여 해당 로직을 메서드 실행 전후에 삽입
4. Advice 유형과 사용법
1) @Before - 메서드 실행 전 처리
@Before("execution(* com.example.service.*.*(..))")
public void beforeAdvice(JoinPoint joinPoint) {
System.out.println("메서드 실행 전: " + joinPoint.getSignature().getName());
}
- Target 객체의 메서드가 실행되기 전에 실행되는 Advice
- joinPoint를 통해 메서드 이름 및 파라미터 정보 조회 가능
2) @After - 메서드 실행 후 처리 (예외 발생 여부 무관)
@After("execution(* com.example.service.*.*(..))")
public void afterAdvice(JoinPoint joinPoint) {
System.out.println("메서드 실행 후: " + joinPoint.getSignature().getName());
}
- 메서드가 정상 종료되든, 예외가 발생하든 무조건 실행됨
- 리턴값이나 예외 정보를 직접 전달받지는 못함
3) @Around - 메서드 실행 전후 처리 (가장 강력한 Advice)
@Around("execution(* com.example.service.*.*(..))")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = joinPoint.proceed(); // 메서드 실행
long endTime = System.currentTimeMillis();
System.out.println("메서드 실행 시간: " + (endTime - startTime) + "ms");
return result;
}
- joinPoint.proceed()를 호출해야 Target 메서드가 실행됨
- 실행 전후의 로직을 모두 제어할 수 있어 가장 유연한 방식
4) @AfterReturning - 정상 실행 후 처리
@AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")
public void afterReturningAdvice(JoinPoint joinPoint, Object result) {
System.out.println("메서드 정상 종료: " + joinPoint.getSignature().getName() + " 반환값: " + result);
}
- 메서드가 정상적으로 실행된 후 실행됨
- returning 속성에 리턴값을 받을 변수명을 지정하여 리턴값 활용 가능
5) @AfterThrowing - 예외 발생 시 처리
@AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "ex")
public void afterThrowingAdvice(JoinPoint joinPoint, Throwable ex) {
System.out.println("메서드 실행 중 예외 발생: " + joinPoint.getSignature().getName() + " 예외: " + ex.getMessage());
}
- 예외가 발생한 경우 실행됨
- throwing 속성에 발생한 예외를 받을 변수명을 지정
결론
AOP는 비즈니스 로직과 공통 관심 사항을 분리하여 코드 중복을 줄이고 유지보수성을 높일 수 있기 때문에 보다 효율적이고 확장성 있는 서비스를 개발할 수 있다.
'Spring Boot' 카테고리의 다른 글
[Spring Boot] Filter와 Interceptor (0) | 2025.02.02 |
---|---|
[Spring Boot] Redisson 분산 락 (0) | 2024.06.09 |
[Spring Boot] OTP 2차 인증 (0) | 2024.04.30 |