Enterprise Java 환경에서 최근 가장 주목받는 기술 중 하나는 AOP, 즉 Aspected Oriented Programming 이다. AOP가 주목받는 이유는 Enterprise Java 시스템이 맞닥뜨리고 있는 복잡성때문이다.

 

(AOP의 정의에 대해서는 Wikipedia를 참조하기 바란다)

 

AOP는 전통적인 객체 지향의 프로그래밍(Object Oriented Programming. 이하 OOP)이 실패한 곳에서 진가를 발휘한다. OOP 언어들은 견고한 철학과 다양하고 유연한 프로그래밍 기법, 다양한 패턴들의 체계화등을 제공한다. 프로그래머들은 이로 인해 절차식 프로그래밍 언어들을 사용할 때에 비해 훨씬 직관적이고 체계적이고 모듈화된 구현을 할 수 있게 되었다. 만세!!!

 

하지만, 불행히도 OOP 언어가 해결하지 못하는 몇가지 중요한 문제점들이 대두되었다.

 

가장 간단하고 직관적인 예로 로깅(Logging) 기능을 생각해 보자. OOP 언어의 대표격인 Java에서의 전통적인 Logging 구현 방법은 다음과 같다.

public class OrderManager {

 public void orderItem(OrderItem oi) {
  Logger log = Logger.getLogger("order");
  log.info("orderItem started...");
  // do something
  try {
   doSomething(oi);
  } catch(Exception ex) {
   log.info("Error : " + ex.getMessage());
  } finally {
   log.info("orderItem finished...");
  }
 }


   

Logger라는 객체를 이용해서 로깅 기능을 잘 모듈화했지만, 실제 이 객체를 사용하다보면 몇가지 심각한 문제를 만나게 된다.

  • 로직을 구현하는 핵심 소스에 많은 수의 로깅 관련 소스가 삽입됨으로써 소스의 가독성과 간결함을 심하게 훼손한다.
  • 로깅을 남기는 방법이나 시점, 위치 등을 바꾸려면 거의 모든 소스파일을 변경해야 한다.

위와 같이 "어떻게 하면 로깅을 남기는 기능을 핵심 로직과 무관하게 구분해서 구현할 수 있을까"라는 간단하고 명확한 요구에 대해 OOP는 적절한 대답을 하지 못한다. 여기가 AOP가 개입되는 부분이다.

 

AOP는 객체를 프로그래밍 단위로 하지 않고, 특정 사건의 발생 양상(또는 상황/국면)을 프로그래밍의 단위로 한다. 이런 의미에서 AOP를 한글로 번역하자면 상황 지향 프로그래밍이 가장 적절한 것으로 생각된다.

 

위의 로깅 예제에서는 다음과 같은 상황들이 펼쳐진다.

  1. orderItem 메소드가 시작하는 상황에 로그를 기록하라.
  2. orderItem 메소드가 끝나는 상황에 로그를 기록하라.
  3. orderItem 메소드내에서 Exception이 발생하는 상황에 로그를 기록하라.

AOP에서는 위의 상황들을 정의할 수 있고, 이런 상황이 발생했을 때 수행할 작업을 정의할 수 있다. 즉, 핵심 로직과 무관하게 핵심 로직을 수행하는 과정에서 발생하는 상황들을 적절하게 다룰 수 있다.

 

Java AOP의 대표적인 언어인 AspectJ를 이용하면 위의 소스를 다음과 같이 변경할 수 있다.

 

// 놀랍게도 핵심 로직에서는 Logging 관련된 부분이 완전히 제거된다.

public class OrderManager {

 public void orderItem(OrderItem oi) {
  // do something
  try {
   doSomething(oi);
  } catch(Exception ex) { }
 }


 

// 핵심 로직에서 발생하는 상황에 대한 로직을 구현한다.

public aspect LoggingAspect {

 // OrderManger내에서 발생하는 모든 Method Call에 대해

 pointcut methodExec() :
   call(* *.*(..)) && within(OrderManager);
 

 // Method Call 시작시 수행할 일

 before() : methodExec() {
  Logger log = Logger.getLogger("order");
  log.info(thisJoinPointStaticPart.getSignature() + " started...");
 }
 

 // Method Call 종료시 수행할 일
 after() returning : methodExec() {
  Logger log = Logger.getLogger("order");
  log.info(thisJoinPointStaticPart.getSignature() + " finished...");
 }
 

 // Exception 발생시
 after() throwing(RuntimeException ex) : methodExec() {
  Logger log = Logger.getLogger("order");
  log.info("Error : " + ex.getMessage());
 }
}

 

위와 같이 AOP를 이용하면 로깅과 같은 Aspect라는 이름으로 비핵심 로직을 핵심 로직에서 완전히 분리할 수 있으며, 이후 로깅과 관련된 변경 사항은 핵심 로직을 담당하는 소스의 변경이 아닌 Aspect의 변경만으로 이루어진다.

지금까지 AOP의 등장 배경에 대해 간략하게 살펴보았다. 다음 글을 통해 AOP의 개념 및 AOP의 대표 구현체인 AspectJ에 대해 좀 더 상세하게 논의해보자.

 

출처 : 복사 http://blog.naver.com/ukja/


YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST