[Spring] AOP(Aspect Oriented Programming) 정리

2

StudySpring

목록 보기
1/2
post-thumbnail

안녕하세요. 오늘은 Spring AOP에 대해서 정리해보고자 합니다.


1. AOP가 왜 나왔을까?

AOP는 코드의 중복을 막고, 부가기능을 따로 뺌으로써 유지보수성을 높이기 위해 출시된 기법입니다.

아래의 비즈니스 로직에서, 시간 측정하는 기능을 넣어봅시다.

public void join(JoinRequest joinRequest) {
	memberRepository.save(joinRequest.toMember());
}

시간 측정 기능 추가를 위해, 아래처럼 try-finally문을 작성할 수 있습니다.

public void joinMember(JoinRequest joinRequest) {
	StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    try {
    	memberRepository.save(joinRequest.toMember());
    } finally {
    	stopWatch.stop();
        log.info("join spent {} ms", stopWatch.getLastTaskTimeMillis());
    }
}

한 메서드에서는 기능의 추가가 쉽지만, 실제 운영 로직에는 수백, 수천개의 메서드가 있습니다. 모든 메서드에 시간 측정 기능을 추가하기 위해 위의 try-finally문을 넣는다면, 이는 굉장한 시간낭비입니다.
서비스에서 필요한 내용은 "비즈니스 로직" 이라고 불리는 핵심기능입니다. 그 외 시간을 잰다던지, 트랜잭션을 건다던지 하는 기능들은 "인프라 로직", 즉 부가기능입니다.
인프라 로직(부가기능)은 애플리케이션의 전 영역에서 나타날 수 있으며, 그렇기 때문에 중복코드를 만들어 낼 가능성이 있습니다. 중복코드가 있으면 당연히 유지보수가 힘들어집니다. 또한, 비즈니스 로직과 함께 있으면 비즈니스 로직을 이해하기가 어려워집니다.
인프라 로직(부가기능)은 로깅, 권한 체크 등 하나의 관심사를 가지게 됩니다. 따라서, 인프라 로직의 중복이 "횡단"으로 나타나게 됩니다.

2. AOP(Aspect-Oriented Programming)란?

AOP는 여러 오브젝트에 나타나는 공통적인 부가 기능을 모듈화하여 재사용하는 기법입니다. 앞에서 나온 "횡단 관심사"에 따라 프로그래밍한다고 생각하면 편합니다.

3. 어떤 부가기능을 언제, 어디에 재사용해야할까?

AOP에 대해 알았으니, 이제 어떤 부가기능을 언제, 어디에 재사용할지를 생각해봐야 합니다. 이를 위해 등장한 개념이 바로 Target, Advice, Join Point, Point Cut입니다.

✔ Advice: "어떤" 부가기능을 "언제" 사용할지에 대한 정의

Advice는 어떤 부가기능을 언제 사용할지에 대한 정의입니다. 이 때, 언제 사용할지에 따라 Before, AfterReturning, AfterThrowing, After, Around 총 다섯가지로 나뉩니다.

  • before
    - 메서드가 실행되기 전에 사용되는 advice
  • afterReturning
    - 메서드가 정상적으로 실행되었을 때 사용되는 advice
  • afterThrowing
    - 메서드가 예외를 발생시키는 경우에 대해서 사용되는 advice
  • after
    - afterReturning + afterthrowing
    • 정상적으로 실행되거나 또는 예외를 발생시켰을 때 모두 사용되는 advice
  • around
    - 비즈니스 전 후 모두에 실행되는 Advice
    • 우리 예제인 시간측정 기능에서 사용되는 advice

✔ JoinPoint: Advice를 적용시킬 위치

JoinPoint는 Advice를 적용시킬 위치를 말합니다. Advice를 적용시킬 수 있는 위치에는 1) 메서드를 호출할 때, 2) 변수에 접근할 때, 3) 객체를 초기화할 때, 4) 객체에 접근할 때 가 있습니다. 하지만 Spring AOP는 프록시 기반의 AOP이기 때문에, 메서드를 호출할 때만 사용할 수 있습니다. 따라서, Spring AOP에서 JoinPoint라고 하면 그냥 메서드를 호출할 때라고 봐도 무방합니다.

JoinPoint 개념을 익힌 후, 시간측정 부가기능이 getMember, joinMember, deleteMember 모두에 적용된 모습입니다.


하지만, 예제에서는 모든 메서드에 적용되는 것이 아닌, joinMember에만 시간측정이 적용되기를 원합니다. 이럴 때는 PointCut 개념을 사용해야 합니다.

✔ PointCut: 실제 Advice가 적용될 지점

PointCut은 Advice를 적용할 JoinPoint를 선별하는 것을 말합니다. 원하는 것을 선택하는 작업, 원하는 것을 선택하는 작업을 말합니다.

PointCut을 정의함으로써, joinMember 메서드에만 시간측정 기능을 추가한 모습입니다.

✔ Target: 부가기능이 적용될 대상

Target은 Advice가 적용되는 대상입니다. 예제에서는 joinMember이 Target에 해당되고, 나머지 메서드는 Target에 해당되지 않습니다.

4. 실제 Advice 구현 예시

예시에서 사용한 stopWatch 기능을 구현한 모습입니다. PerformanceCheck이라는 커스텀 어노테이션 기반으로 PointCut을 지정했습니다. PerformanceCheck이라는 어노테이션을 단 메서드는 시간측정기능을 적용한다는 뜻입니다.

@Around("@annotation(PerformanceCheck)")
public Object stopWatch(ProceedingJoinPoint joinPoint) throws Throwable {
	StopWatch stopWatch = new StopWatch();
    try {
    	stopWatch.start();
        return joinPoint.proceed();
    } finally {
    	stopWatch.stop();
        log.info("request spent {} ms", stopWatch.getLastTaskTimeMillis();
    }
}

[참고한 곳]

테코톡 - Spring AOP1
테코톡 - Spring AOP2

0개의 댓글