[Spring] AOP (Aspect-Oriented Programming) 기본과 개념

반응형

Spring에는 AOP(Aspect-Oriented Programming, 관점 지향 프로그래밍)이라는 핵심 기능을 제공합니다. 음? OOP(객체 지향 프로그래밍)라는 것은 들어봤는데, AOP는 무엇일까요?

 

 

 

AOP vs OOP ?

관점 지향 프로그래밍(AOP)은 애플리케이션에서 코드가 중복되고 강력하게 결합되어 다른 로직과 분리할 수 없는 애플리케이션 로직들을 별도의 관심사로 분리하여 모듈회 하는 프로그래밍 방법입니다.

 

우리는 보통 이러한 로직을 만났을 때 코드를 복제하여 의존성을 만들게 되는데, AOP는 이러한 의존성 없이도 동작하게 해줍니다. 대표적으로 logging 코드들이 여기에 해당합니다.

 

그렇다면 AOP와 OOP는 서로 경쟁하는 관계인가요?

 

그것은 아닙니다. 왜냐하면 우리는 OOP만을 가지고 전체 애플리케이션을 개발할 수 있지만 AOP만 가지고 전체 애플리케이션을 개발할 수 없기 때문입니다. 따라서 AOP를 배우기 위해서는 반드시 OOP에 대한 개념을 확실히 숙지한 뒤에 공부하는 것을 권장합니다.

 

단순하게 본다면 저 클래스를 추상 클래스로 바꾸고 해당 클래스를 상속할 때 super 키워드를 사용해 넣을 수도 있을 것입니다. 하지만 여전히 중복된 코드가 발생되는 것은 동일합니다. 우리는 이를 '흩어진 관심사(Crosscutting concerns)'라고 합니다.

즉, 쉽게 얘기하면 이 클래스의 핵심 로직이 아니지만 반복해서 쓰이는 관심 로직입니다.

 

 

 

AOP 개념

관점 지향 프로그래밍에는 쓰이는 고유의 개념과 용어를 알아보겠습니다. 

 

  • Aspect

    애플리케이션에 포함해야 하는 로직과 해당 로직이 어디서 실행해야 하는지를 정의한 코드

  • Target

    Aspect를 적용한 객체 (종종 adviced object라고도 함)

  • Advice

    특정 조인포인트에 실행되는 코드로 애플리케이션 클래스 내 메서드로 정의 (예: before, after)

  • JoinPoint

    애플리케이션 실행 과정 중 Advice가 적용될 지점
    예) 메서드 명시적 호출(call), 메서드 참조 호출(invoke), 클래스 초기화, 객체 인스턴스 생성할 때 등

  • PointCut

    언제 Advice를 실행할지를 정의할 때 사용하는 조인포인트의 모음으로 위에서 설명한 예시 상황 외에 다른 별도의 상황을 명시할 수 있음.
    예) 특정 메서드 호출시, 특정 클래스의 변수가 어떠한 값일 때 등

  • Weaving

    애플리케이션 코드의 적절한 위치에 Aspect를 삽입하는 과정.
    일반적으로 AOP 솔루션에서 컴파일 시점에서 위빙은 빌드 시점에 수행하고, 런타임 시점에서는 런타임에 동적으로 실행.

    AspectJ에서는 위 시점 외에 로드 시점 위빙(Load-Time Weaving)이라는 매커니즘 제공, 
    이 방식은 내부 JVM Class Loader가 바이트 코드를 로딩할 때 해당 바이트 코드에 위빙 기능을 제공해주는 것임.

  • Introduction

    추가 메서드나 필드를 도입해 객체의 구조를 수정하는 과정. 
    이를 사용하면 명시적으로 특정 인터페이스 구현 없이 모든 객체가 해당 인터페이스를 구현할 수 있음.

 

 

AOP 실전

그럼 이제 AOP가 어떻게 동작하는지 알아보겠습니다. 간단하게 AOP를 사용해서 Hello World를 구현해보도록 하죠.

 

저자라는 클래스를 만들고, 저자 이름을 출력하는 메서드인 print 메서드를 만들어줬습니다. 여기서 원하는 것은 저자 이름을 출력할 때 반드시 저자 이름 앞에 "Author"가 같이 출력되도록 하도록 하는 것입니다.

 

이름을 출력하는 메서드를 호출할 때 앞에 "Author"를 출력하도록 Advice를 하나 추가합니다.

 

이를 위해 MethodInterceptor라는 인터페이스를 사용할 수 있습니다. MethodInterceptor는 메서드 호출 JoinPoint에 적용할 Around Advice를 구현할 때 사용하는 표준 AOP Aliance Interface입니다. 이와 비슷한 녀석으로 Enhancer가 있습니다.

 

여기에 메서드 인자로 사용되는 MethodInvocation은 Advice를 추가하는 메서드 호출을 나타내며 이 객체를 사용해 메서드 호출되는 시점을 제어할 수 있습니다.

 

코드에 보면 retVal(return value)이라는 변수가 보입니다. 실제로 우리가 Target 객체의 메서드를 호출했을 때 반환되는 값으로 해당 메서드를 추적해보면 이 메서드가 JoinPoint의 메서드임을 알 수 있습니다.

 

따라서 순서대로 진행해보면 N.K를 간단히 출력하기 전, Author를 출력하고 그 다음에는 !를 출력하는 형태가 되는 것입니다.

 

마지막으로 AuthorDecorator 어드바이스를 코드에 위빙해야 합니다. Advice를 위빙할 때는 먼저 Advice 적용 대상인 Author의 인스턴스를 생성하고 해당 인스턴스의 적용할 프록시를 생성한 다음 ProxyFactory가 AuthorDecorator 어드바이스를 위빙하도록 하면 됩니다.

 

여기서 중요한 점은 ProxyFactory 클래스를 사용하여 대상 객체의 프록시를 생성함과 동시에 어드바익스를 위빙한다는 점이며 Enhancer를 이용할 때와는 조금 다릅니다.

 

addAdvice를 호출하여 ProxyFactory에 AuthorDecorator 어드바이스를 전달하고 setTarget을 호출해 위빙 대상을 지정하면 됩니다.

 

출력 화면을 보면 수정하지 않은 Target 객체에서 print()를 호출하면 표준 메서드 호출이 이뤄지고, 프록시를 사용해 호출하면 AuthorDecorator의 코드가 실행되어 앞에 "Author"가 표시되는 것을 볼 수 있습니다. 

 

자세히 보면 관심된 로직을 원하는 클래스에 적용하기 위해 프록시 객체를 사용했고, 프록시 객체를 사용했기 때문에 실제 클래스에서는 어떠한 의존성도 갖고 있지 않습니다.

 

그저 해당 관심 로직을 처리하기 위해 별도의 프록시 객체를 만들어 관심 로직을 적용해 사용하는 것을 알 수 있습니다.

 

프록시 객체가 이들 로직을 대신 추가해준다는 것인가요?

 

정확하게는 Author라는 객체를 상속받아 새로운 프록시 객체를 만들고 호출한 메서드를 Overriding하는 것입니다. 따라서 클래스를 final class로 정의하거나 호출하는 메서드를 final로 선언하는 경우, IllegalArgumentException을 발생하거나 아예 메서드가 호출되지 않습니다.

 

 

 

마치며...

Spring에서 제공하는 AOP를 다뤄보기 전에 실제 AOP가 무엇인지에 대해 개념을 알아봤습니다. 실제로 Spring AOP는 DI 개념을 이용해 Bean을 생성하는 등 일반적인 Java를 사용할 때와 좀 다른 방법을 이용합니다. 

 

하지만 Spring boot에서 제공하는 AOP는 이보다 더 간단하게 어노테이션(Annotation)을 이용해 더 쉽고 빠르게 AOP를 할 수 있도록 Bean 생성 등을 아주 간소화 하였으며 이러한 함축된 개념을 좀 더 살펴보기 위해 이 글을 작성하게 되었습니다.

 

다음 글에서는 Spring AOP의 아키텍처와 이를 사용하는 방법에 대해 적어보도록 하겠습니다.

 

 

 
반응형

Tistory Comments 0