AOP 

Aspect Oriented Programming

관점 지향적 프로그래밍

 

 

공통의 관심사를 모듈화하여 핵심 로직과 분리하는데 집중

ex) 로깅, 트랜잭션, 보안 등

 

얘네는 반복되면서 중요한 작업이지만, 비즈니스 로직과는 분리가 필요한 기능들

 

 

 

 

용어 정리

  • Aspect: 공통 관심사 (예: 로그 출력)
  • Join point: Advice가 적용될 수 있는 지점 (예: 메서드 실행)
  • Advice: 언제 무엇을 실행할지 정의하는 코드 (예: @Before, @After)
  • Pointcut: Advice가 적용될 join point를 선정하는 식
  • Weaving: Advice를 실제 객체에 적용하는 과정 (런타임에 프록시 방식으로)

 

 

Aspect 종류

 

Before Advice @Before 대상 메서드 실행 전에 실행됨
After (finally) Advice @After 대상 메서드 성공/실패 여부와 관계없이 종료 후 실행
After Returning Advice @AfterReturning 대상 메서드가 정상 종료되었을 때만 실행
After Throwing Advice @AfterThrowing 대상 메서드에서 예외가 발생했을 때만 실행
Around Advice @Around 대상 메서드의 실행 전/후 모두 제어 가능하며 proceed()를 통해 직접 실행함

 

대부분의 경우 Around Advice 사용해서 구현 가능

 

 

 

구현

 

@Aspect
@Component
public class LoggingAspect {

    @Before("execution(* com.example.service.*.*(..))")
    public void logBefore() {
        System.out.println("[Before] 메서드 실행 전 로그 출력");
    }

    @After("execution(* com.example.service.*.*(..))")
    public void logAfter() {
        System.out.println("[After] 메서드 실행 후 로그 출력");
    }
}

Aspect 클래스 정의

ex) 로깅을 위한 클래스

 

** excution 으로 point cut 지정

execution(...) 메서드 실행 지점을 의미하는 포인트컷 타입
* 반환 타입: 모든 반환 타입 허용 (void, int, String, 등)
com.example.service.* 패키지: com.example.service 하위의 모든 클래스 (바로 아래 클래스만 포함, 하위 패키지는 포함되지 않음)
* 클래스 내 모든 메서드 이름
(..) 메서드 인자: 매개변수 개수와 타입에 상관없이 전부 허용

point cut 표현식은

수식어, 리턴타입, 클래스 이름, 파라미터 등에 대해 조건 명시 가능

 

@Service
public class SampleService {
    public void doSomething() {
        System.out.println("핵심 로직 수행");
    }
}

 excution point cut 표현식 조건에 맞는 메서드가 실행 될 때, 전 후로 aspect 메서드 수행

 

[Before] 메서드 실행 전 로그 출력
핵심 로직 수행
[After] 메서드 실행 후 로그 출력

 

 

 

Pointcut

  • 하나의 Pointcut 에 여러 Advice를 적용할 수 있으며, 어떤 Aspect가 먼저 적용될지는 스프링 프레임워크나 자바 버전에 따라 달라질 수 있음
  • Aspect 적용 순서가 중요하다면 @Aspect 애노테이션과 함께 @Order 애노테이션을 붙여 적용 순서 결정 가능
@Aspect
@Order(1)
public class FirstAspect {
}

@Aspect
@Order(2)
public class SecondAspect {
}

 

  • @Pointcut 애노테이션이 아닌 @Around 애노테이션에 execution 명시자를 직접 지정할 수도 있음
@Aspect
public class ExamAspect {

	@Around("execution(public * package..*(..))")
    public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
    	...
    }

}

 

+ Recent posts