[Spring / 스프링] AOP | 관점지향이란 | 사용법

관점지향 프로그래밍 AOP(Aspect Oriented Programming)는 관점을 기준으로 하는 프로그래밍을 의미합니다. 정의를 읽는 것만으로는 이해하기가 어려울 것입니다. AOP를 이해하기에 앞서 프로그래밍의 발전 과정을 간단하게 짚어보면 도움이 됩니다.

 

프로그래밍은 절차지향 → 객체지향 → 관점지향 순으로 발전했습니다. 절차지향 PP(Procedural Programming)는 코드를 작성한 순서대로, 즉 위에서부터 아래로 한 줄 한 줄 수행합니다. 절차지향적으로만 구성된 프로그램은 코드 중복이 많을 수밖에 없습니다. 윗 줄에서 구현한 코드를 아랫 줄에서 또 사용하는 경우가 많을 테니까요. 

 

이런 단점을 보완하는 게 객체지향 프로그래밍 OOP(Object Oriented Programming)입니다. 여러 클래스 객체를 만들어 놓고 필요할 때마다 호출해서 사용하는 게 핵심입니다. OOP에서 모듈화의 단위는 클래스입니다.

 

이제 AOP가 등장 합니다. OOP, AOP 어딘가 비슷해 보이죠? 따로 모듈을 만들어 놓고 필요할 때 불러서 쓴다는 이 개념이 AOP에서도 마찬가지로 적용됩니다. 다만 AOP에서 모듈화 단위는 관점(Aspect)입니다. Aspect란 여러 클래스에 적용되는 concern을 모듈화 한 것입니다. concern에 대해서는 아래부터 자세히 설명하겠습니다.

Core Concern vs Crosscutting Concern

concern은 Core Concern과 Crosscutting Concern으로 분류합니다. 결론부터 말하면 AOP에서 다뤄야하는 건 Crosscutting Concern입니다. 찾아보니 두 용어의 번역은 다양하게 사용되고 있네요. 이 글에선 핵심관심사항(Core Concern)과 공통관심사항(Crosscutting Concern)으로 부르겠습니다.

 

핵심관심사항은 사용자에게 기능을 제공하기 위한 비즈니스 로직을 의미합니다. 일반적으로 프로그래밍 기능을 구현할 때 작성하는 코드라고 보면 돼요. 공통관심사항은 프로그램 전반에 걸쳐 반복적으로 필요한 기능을 말합니다. 

 

예를 들어 보겠습니다. 계좌이체를 기능을 제공하는 프로그램에서 계좌이체 기능은 핵심관심사항 입니다. 반면 계좌이체에 실패할 경우 관련된 모든 로직을 무효화하는 트랜잭션은 공통관심사항 입니다. 또 어떤 기능이 수행되고 완료되기까지의 시간을 측정하는 것처럼 사용자에겐 아무 영향이 없지만 개발자 입장에서 필요한 보조 코드 역시 공통관심사항의 영역입니다.

 

트랜잭션과 시간측정.. 대충 감이 오시죠? 공통관심사항은 특정 코드가 수행하기 전·후로 삽입되어 수행하는 패턴을 보입니다. 굳이 분류를 하긴 했지만 두 concern은 런타임 시에 모두 동작해야 됩니다.

 

이때 중요한 것이 핵심관심사항과 공통관심사항이 전혀 관계가 없도록 만드는 일입니다. 코드가 서로 영향을 받지 않도록요. 

AOP가 구현되는 구조

참고: 모듈 A, B, C로 만들려고 했는데 실수로 A A A로 만들었다

그림에서 회색으로 표시된 네모박스가 공통관심사항코드 입니다. 모듈 안에서 메서드의 앞,뒤로 삽입되어 사용됩니다. 코드 내용은 모두 같습니다. 같은 코드를 계속 써주기가 싫으니 하나만 써놓고 그것을 재사용하고 싶겠죠. AOP 프레임워크가 그 일을 도와줍니다. 심지어 모듈에는 아무런 코딩을 하지 않아도 공통관심사항 코드가 작동하도록 해줍니다. 이로써 유지 보수, 재사용에 강점을 갖게 되는 것입니다. 

 

이때 Aspect를 연결하고 객체를 생성하는 것을 위빙(weaving)이라 부릅니다. 위빙을 하는 방법은 3가지인데요. 1. 컴파일 할 때 위빙 2. 클래스 로딩할 때 위빙 3. 런타임 시 위빙.

사실 3번만 기억해도 됩니다. 스프링은 런타임 시 위빙 하는 프록시 기반의 AOP를 지원하니까요.

AOP 구현 방식

1. xml 기반 POJO 클래스 이용

우선 xml 파일에 명시해주는 방법이 있습니다. aop 태그를 이용합니다.

<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:aop="http://www.springframework.org/schema/aop"
      xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

   <!-- this is the object that will be proxied by Spring's AOP infrastructure -->
   <bean id="fooService" class="x.y.service.DefaultFooService"/>

   <!-- this is the actual advice itself -->
   <bean id="profiler" class="x.y.SimpleProfiler"/>

   <aop:config>
      <aop:aspect ref="profiler">

         <aop:pointcut id="theExecutionOfSomeFooServiceMethod"
                    expression="execution(* x.y.service.FooService.getFoo(String,int))
                    and args(name, age)"/>

         <aop:around pointcut-ref="theExecutionOfSomeFooServiceMethod"
                  method="profile"/>

      </aop:aspect>
   </aop:config>

</beans>

aspect로 지정할 클래스를 선택하고 pointcut 태그로 어떤 메서드에 advice를 구현할지 명시합니다. advice란 aspect에 의해 수행되는 액션(ex. around, before, after)을 의미합니다. around 태그는 핵심 로직 앞뒤로 공통 로직을 수행할 때 사용됩니다. 

2. annotation 이용

어노테이션을 이용하기 위해선 xml 파일에 "aop 어노테이션을 사용할게"라고 명시해 줘야 합니다.

<aop:aspectj-autoproxy/>

이렇게 오토 프록시 패턴을 사용하겠다고 명시하면 됩니다. 이제 클래스에서 구현할 수 있습니다.

package org.xyz;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;

@Aspect
public class NotVeryUsefulAspect {

    @Pointcut("execution(public * *(..)") // 표현식
    private void profileTarget() {}

    @Around("profileTarget()")
      public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
    // start stopwatch
    Object retVal = pjp.proceed();
    // stop stopwatch
    return retVal;
  }
}

위 코드를 보면 profileTarget()이라는 기능 없는 코드에 @Pointcut을 심고 해당 메서드가 수행될 때 @Around를 수행시키고 있습니다. "execution(public * *(..)"은 접근제어자가 public인 모든 메서드에 적용하겠다는 표현식입니다. 이 같은 표현식의 종류가 매우 다양하니 원하는 형태로 사용하면 됩니다.


예제 출처 및 내용 참고: spring-framework 문서

반응형

댓글

Designed by JB FACTORY