본문으로 바로가기

스프링의 AOP 란?

category 스프링 2020. 6. 23. 00:53

스프링의 핵심 중 하나인 AOP는 Aspect Oriented Programing의 약자이다.
관점 지향 프로그래밍이라고 불리우는 AOP는 쉽게 말해 코드를 작성할 때 핵심적인 관점과 부가적인 관점으로 나누어서 작성하고 그 기준으로 각각 모듈화 하겠다는 기법이다.

좋은 개발환경 원칙은 '개발자가 비지니스 로직에만 집중할 수 있게 한다.'입니다. 이 원칙을 위해선 여러가지 방법이 있겠지만 가장 단순하게는 반복적인 코드를 줄이는 것에 있습니다.

이때 반복적인 코드를 흩어진 관심사(Crosscutting Concerns)라고 부릅니다.
이 AOP에서 말하는 흩어진 관심사들은 부가 기능 관점에서 바라본 관심사들입니다. 대표적 예로 로깅, 트랜잭션, 보안 등과 같은 기능들입니다.

클래스 A,B,C는 핵심관점이고 X,Y,Z는 부가적관점으로 Aspect 입니다.

위와 같이 흩어진 관심사를 Aspect로 모듈화 시켜 핵심적인 비지니스 로직에서 분리하여 재사용하겠다는 것이 AOP의 취지입니다.

AOP의 주요 개념

  • Aspect : 공통 관심사에 대한 추상적 명칭. 예를 들어 로깅이나 보안, 트랜잭션과 같은 기능 자체에 대한 용어
  • Advice : 실제로 기능을 구현한 객체
  • Join Points : 여러 메소드 중 실제 Advice가 적용 될 메소드
  • PointCuts : JointPoint의 상세한 스펙을 정의한 것. 'A란 메서드의 진입 시점에 호출할 것'과 같이 더욱 구체적으로 Advice가 실행될 지점을 정할 수 있음
  • Target : Aspect를 적용하는 곳(클래스, 메소드 ..)
  • Proxy : Targer을 감싸는 랩핑(Wrapping) 오브젝트입니다.
  • Introduction : Target에는 없는 새로운 메소드나 인스턴스 변수를 추가하는 기능
  • Weaving : 지정된 객체에 Aspect를 적용해서 새로운 프록시 객체를 생성하는 과정을 얘기합니다.

스프링 AOP 특징

  • 프록시 패턴 기반의 AOP 구현체는 '기존의 코드를 수정하지 않고 코드의 앞이나 뒤에서 필요한 기능이 동작할 수 있게끔 합니다.'
  • 외부에서 특정 객체(Targer)을 호출하면 실제 객체를 감싸고 있는 객체(Proxy)를 통해 호출이 전달 됩니다.

스프링 AOP의 사용

  • @Aspect
    @Component
    @Aspect
    public class AspectTimer {
    @Around("execution("execution(* com.khs.boardService.*(..))")
      public Object timer(ProceedingJoinPoint pjp) throws Throwable{
          long begin = System.currentTimeMillis();
          Object retVal = pjp.proceed();
          System.out.println(System.currentTimeMillis() - begin);
          return retVal;
      }
    }

@Aspect를 명시하고 Aspect 클래스로 정의하고 @Component를 명시하여 빈으로 등록합니다.

@Around는 Target 메소드 전후로 실행하겠다는 의미입니다.
위 코드는 Target 메소드의 실행 시간을 측정하기 위한 코드입니다.
"execution(* com.khs.BoardServiceImpl.*(..))"는 BoardServiceImpl 하위의 모든 메소드에 적용하겠다는 의미입니다.

  • Targer

BoardServiceImpl은 본인의 원래 목적인 Board와 관련된 기능에만 집중하도록 그대로 코드를 보존하고 테스트를 수행해보겠습니다.

@Component
public class BoardServiceImpl implements BoardService {

    @Override
    public void create() {
        try {
            Thread.sleep(1000);
              // 핵심 기능 수행
        } catch(InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Created");
    }

    @Override
    public void update() {
        try {
            Thread.sleep(1000);
            // 핵심 기능 수행
        } catch (InterruptedException e){
            e.printStackTrace();;
        }
        System.out.println("Update");
    }

    public void delete() {
        // 핵심 기능 수행
        System.out.println("Delete");
    }
}
Created
1000
Update
1000
Delete
0

수행시간이 출력되는것을 확인할 수 있습니다.
여기서 중요한 것은 핵심로직을 담당하는 BoardServiceImpl과 BoardService는 전혀 변경이 없었다는 것입니다. 우리가 그토록 원했던 핵심기능과 보조기능이 함께있지만, 코드는 완전히 분리된 상태가 된 것입니다.

제일 먼저 보이는 @Around는 Advice입니다.
앞서 설명드린것 처럼 어드바이스는 애스펙트가 "무엇을", "언제" 할지를 의미하고 있습니다.
여기서 "무엇"은 AspectTimer() 메소드를 나타냅니다.
그리고 "언제"는 @Around가 되는데, 이 언제 라는 시점의 경우 @Around만 존재하지 않고 총 5가지의 타입이 존재합니다.

  • @Before (이전)

    어드바이스 타겟 메소드가 호출되기 전에 어드바이스 기능을 수행

  • @After (이후)

    타겟 메소드의 결과에 관계없이(즉 성공, 예외 관계없이) 타겟 메소드가 완료 되면 어드바이스 기능을 수행

  • @AfterReturning (정상적 반환 이후)

    타겟 메소드가 성공적으로 결과값을 반환 후에 어드바이스 기능을 수행

  • @AfterThrowing (예외 발생 이후)

    타겟 메소드가 수행 중 예외를 던지게 되면 어드바이스 기능을 수행

  • @Around (메소드 실행 전후)

    어드바이스가 타겟 메소드를 감싸서 타겟 메소드 호출전과 후에 어드바이스 기능을 수행

'스프링' 카테고리의 다른 글

검색 처리와 동적 SQL  (2) 2020.07.19
게시글의 페이징 처리  (0) 2020.06.26
스프링의 @ModelAttribute 어노테이션  (0) 2020.06.15
AJAX란?  (0) 2020.06.15
인터셉터(Interceptor)란?  (0) 2020.06.13