Spring Framework AOP

2015. 11. 26. 14:33Framework/Spring Framework

    목차

4. Spring AOP

어플리케이션 전체에 걸쳐 사용돼야 할 기능이 필요한 경우 관점지향 프로그래밍(AOP)를 이용할 수 있다. Spring의 AOP는 어플리케이션 전체에 걸쳐 흩어져 있던 기능을 한 곳에(Aspect) 작성할 수 있다. 예를 들어, 공통적인 기능을 재사용하기 위해 일반적으로 상속이나 위임을 사용할 것이다. 그러나 상속의 경우, 만약 동일한 기초 class가 어플리케이션의 여러 곳에 걸쳐 사용된다면 객체의 계층도를 깨뜨릴 수 있다. 또한 위임은 사용하기 번거로우며, 여전히 위임한 객체에 대한 중복 호출을 필요로 한다.
AOP를 사용하면 공통적인 기능을 한 곳에서 정의할 수 있으며, 새로운 기능을 적용하려고 하는 class를 수정할 필요 없이 그런 기능을 어디에 어떻게 적용할 것인지를 선언적으로 정의할 수 있다. 이렇게 횡단 관심사는 Aspect라고 하는 특별한 객체로 모듈화된다.

※ 각 관심사에 대한 로직이 여러 코드에 분산되지 않고 한 곳에서 관리된다.
※ 어플리케이션은 비즈니스 로직만 정의하면 된다.

4.1. Spring AOP의 능력과 목적

Spring AOP는 순수 자바 언어로 구현되었다. 그리고 AOP를 적용하기 위해서 추가적으로 컴파일을 해 줄 필요가 없다. 더불어 class 로더 계층 구조를 제어해야 할 필요도 없다. 따라서, J2EE 웹 컨테이너나 어플리케이션 서버의 사용에 매우 적합하다고 할 수 있겠다. 
아직까지는 함수 호출의 interception만 지원하고 있다. Spring AOP API는 함수의 필드 interception도 지원하고 있지만, 구현되어 있진 않다.
함수의 필드들까지 interception 하고 싶다면 현재로써는 AOP의 기능들이 좀더 상세하게 구현 된 AspectJ의 사용을 고려하는 대안 밖에는 없을 듯 하다.
Spring은 pointcut들과, 서로 다른 advice 타입들을 나타내기 위해서 advisor라는 class를 사용한다. advisor는, advice와 pointcut을 포함하는 aspect와 같다고 할 수 있다.
Spring AOP는 다른 대부분의 AOP framework들과 비교하여, AOP라는 개념에 접근하는데에 있어서 꽤 많은 차이점을 가진다.
다른 AOP framework들이 AOP의 완벽한 구현 자체에 촛점이 맞추어져서 완성 된 반면, Spring AOP는 Spring IoC와 AOP 기술을 긴밀히 접목시켜서 현존하는 엔터프라이즈 애플리케이션의 문제점들을 단순하고 쉽게 극복하는데 그 구현의 목적이 있다.

4.2. AOP 용어와 Spring에서의 적용

아래 설명 될 용어는 Spring의 AOP를 위해서만 쓰여지는 용어들이 아니라, 우리가 통상적으로 인식하는 모든 AOP의 개념들을 말할 때, 사용되어 질 수 있는 용어들이다.

1) Joinpoint
class의 인스턴스 생성 시점, 메소드를 호출하는 시점, Exception이 발생하는 시점과 같이 어플리케이션을 실행할 때 특정 작업이 실행되는 시점을 의미한다.
Aspect를 플러그인할 수 있는 어플리케이션의 실행 지점. 메소드, 예외, 변경 가능한 필드가 될 수 있다. 이들 지점은 새로운 기능을 추가하기 위해 어플리케이션의 정상적인 흐름에 Aspect의 코드가 삽입되는 위치.

2) Advice
Logging, SendEmail과 같이 실질적인 비즈니스 로직을 구현하고 있는 UserServiceCore에 추가적인 기능을 제공하는 것. 또는 Target class에 추가적인 기능을 지원하기 위한 목적으로 사용되는 것.
Aspect의 실제 구현체. 어플리케이션에게 새로운 행위를 충고한다.

▤ Before Advice
org.springframework.aop.MethodBeforeAdvice 인터페이스의 before() 메소드를 구현함으로써 사용 가능한 Advice로 Target class의 메소드가 실행되기 전에 기능을 추가하고 싶을 때 사용한다. 단, Target class의 메소드와 인자에 접근하는 것은 가능하지만 메소드에 대한 직접적인 제어는 할 수 없다.

▤ After Advice
org.springframework.aop.AfterReturningAdvice 인터페이스의 afterReturning() 메소드를 구현하여 Target class의 메소드 실행이 완료된 다음 후처리 작업이 필요할 경우에 사용. After Returning Advice의 경우 메소드 실행 후 반환되는 결과 값에 접근하는 것이 가능하다.

▤ Around Advice
Target class의 메소드, 인자에 대한 정보뿐만 아니라 Target class의 메소드에 대한 직접적인 제어가 가능하다.

▤ Throws Advice
Target class의 메소드 내에서 Exception이 발생했을 때 적용되는 Advice.

▤ Introduction Advice
Target class에 완전히 새로운 기능을 추가하는 것이 가능하도록 지원한다.

3) Pointcut

분리된 기능들을 결합시키기 위한 규칙이 필요했다. 이와 같은 패턴을 의미한다.
Target class와 Advice가 결합(Weaving)될 때 둘 사이의 결합 규칙을 정의하는 것이다. Advice가 어떤 Joinpoint에 적용돼야 하는지를 정의.

▤ StaticMethodMatcherPointcut
Target class의 정적인 정보(class 이름, 메소드 이름)를 기반으로 Pointcut을 만들고자 할 때 사용하는 class. Abstract method 인 *matches(Method method, Class targetClass)*를 구현하여야 한다.

▤ DynamicMethodMatcherPointcut
Target class의 정적인 정보를 포함하여 동적인 정보(메소드 호출 시 전달되는 인자 값)를 기반으로 Pointcut을 만들고자 할 때 사용하는 class이다.
Abstract method인 *matches(Method method, Class targetClass, Object[] args)* 를 구현하여야 한다.

▤ Perl5RegexpMethodPointcut, JdkRegexpMethodPointcut
Perl5 형식, jdk에서 지원하는 정규 표현식을 이용하는 것이 가능하도록 지원하고 있다.

▤ NameMatchMethodPointcut
Pointcut에 전달되는 메소드 이름에 해당하는 메소드에 대해서만 Advice가 적용되도록 지원한다.

▤ ComposablePointcut
union()과 intersection()을 지원함으로써 두 개 이상의 Pointcut을 결합하기 위하여 사용된다.

▤ CotrolFlowPointcut
Target class 메소드 하위에서 특정 패턴에 일치하는 메소드에 대해서만 Advice를 적용하도록 지원하고 있다.

4) Introduction
target class에 method나 field를 추가할 수 있다. Spring은 모든 target class에 새로운 인터페이스를 적용 시킬 수 있다. 특정 class의 caching 처리를 위해서 우리는 isModified를 포함한 인터페이스를 Introduction을 이용하여 구현함으로 쉽게 caching 처리를 하는 class로 둔갑 시킬 수 있다.

5) Aspect
Advice와 Pointcut을 합쳐서 하나의 Aspect라고 한다. 즉, 일정한 패턴을 가지는 클래스에서 Advice를 적용하도록 지원할 수 있는 것. 구현하고자 하는 횡단 관심사의 기능.
어플리케이션의 모듈화하고자 하는 부분. 예를 들면, Logging이다.

6) Weaving
UserServiceCore와 Logging, SendEmail을 결합시키는 것을 의미한다.

7) Target
실질적인 비즈니스 로직을 구현하고 있는 UserServiceCore를 의미한다.

4.3. Spring 프레임워크가 POJO Bean을 생성하는 방법

Spring 프레임워크는 Bean 설정 파일에서 모든 Bean을 관리하기 위하여 세가지 형태로 POJO Bean 생성을 지원하고 있는데 이를 이해해야 ProxyFactioryBean에 대하여 쉽게 이해할 수 있다.

1) new 예약어 방식
new 예약어를 이용하여 인스턴스를 생성하는 것과 같이 인스턴스를 생성한다.

<bean id="userDAO" class="com.paran.user.dao.MyDBUserDAO" />

MyDBUserDAO 인스턴스는 BeanFactory 캐쉬에 저장되었다가 BeanFactory의 getBean() 메소드를 통하여 사용된다. Spring 프레임워크의 Bean 생성을 위하여 가장 많이 사용되는 방법이다.

2) Factory 메소드 방식
이미 개발된 소스를 수정하지 않는 한 new 예약어를 이용하여 인스턴스를 생성하기 힘들 경우 사용한다.

<bean id="aspect" class="com.paran.advice.LoggingAspect" factory-method="aspectOf" />

Bean을 정의할 때 factory-method 속성을 이용하여 인스턴스를 생성하기 위한 메소드 이름을 지정하는 방법.

3) FactoryBean 클래스 방식
FactoryBean 클래스를 만들어서 사용하는 방법이 가장 복잡하지만 가장 많이 사용되는 방법이다. 
특히 다른 프레임워크나 라이브러리와 통합하기 위한 용도로 많이 사용된다.
FactoryBean 클래스가 필요한 이유는 앞의 두가지 방법처럼 인스턴스를 생성하는 방법 이 쉽지 않은 인스턴스를 생성하는 것을 지원하기 위함이다.

4.4. Spring에서의 AOP Proxy

Spring은 default로 J2SE dynamic proxy를 사용한다. J2SE dynamic proxy는 인터페이스만을 proxy 할 수 있다. 
그렇다면, 인터페이스의 구현 자체가 없이 class만을 구현한 object들은 어떠한가? 이때에는, CGLIB를 default로 사용 할 수 있다. 하지만, 항상 인터페이스를 proxy 하기에는 무리수가 따른다.
머지않아 완전히 바이트 코드로 변환되어 proxy하는 형태의 AOP Proxy 추가 타입이 나올 것이다. (프로그램 구현 방식을 변경 할 필요는 없다.)

4.5. ProxyFactoryBean을 이용하여 선언적으로 AOP 적용하기

Spring에서는 프로그램 상에서 ProxyFactory를 사용하여 target class의 proxy를 생성하였지만, Bean Defination 방식으로도 ProxyFactory를 지원하기위하여 ProxyFactoryBean를 제공한다.

4.6. Automatic Proxy 사용하기

AOP를 적용할 때 Bean Definition에서 사용할 Advice나 PointCut을 설정하려면, 모든 Bean에 Aspect설정을 추가해 주어야 한다. 그러나 하나의 Aspect를 만들어 놓고 일정한 패턴을 가지는 모든 Bean에 동일한 Aspect가 적용되도록 처리할 수 있다면 이 작업이 얼마나 쉽게 해결될 수 있겠는가? Spring 프레임워크는 Automatic Proxying이라는 기능
지원을 통하여 이 같은 문제를 해결할 수 있도록 지원하고 있다.

1) DefaultAdvisorAutoProxyCreator
ApplicationContext에서 관리되고 있는 모든 빈에 관련된 Advisor를 적용한다.
Pointcut을 적절하게 사용하여야 한다.

2) BeanNameAutoProxyCreator
Bean defiantion에서 정의 한 Bean의 이름을 기준으로 Aspect를 적용할지의 여부를 결정할 수 있도록 지원한다

4.7. AOP를 이용한 효율적인 개발 전략

하나의 Target 클래스에 너무 많은 Aspect를 적용할 경우 실행 속도의 저하를 가져올 수 있다. 따라서 Aspect는 어플리케이션 개발에 있어서 꼭 필요한 부분에 제한된 범위를 두고서 사용해야 한다.


[출처] - 이 종 화 (ingenuity.egloos.com) -

'Framework > Spring Framework' 카테고리의 다른 글

Spring Framework form 처리  (0) 2015.12.03
Spring Framework MVC  (0) 2015.12.01
Spring Framework Bean 설정 파일 관리  (0) 2015.11.27
Spring Framework IoC  (0) 2015.11.24
Spring Framework 개요  (0) 2015.11.24