본문 바로가기

토비의 스프링3/6장_AOP

Spring AOP(Aspect Oriented Programming)

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

Spring AOP(Aspect Oriented Programming)

 

1. AOP의 목적

 

AOP 개념을 이해하기 전에 "횡단관심사" 라는 단어를 이해할 필요가 있다.

 

횡단관심사 란 보안, 로깅, 트랜젝션 등과 같은 기능들처럼 한 어플리케이션의 여러부분에 걸쳐있는 기능을 의미한다.

즉, 횡단관심사는 한마디로 한 어플리케이션의 여러 부분에 영향을 주는 기능이라고 할 수 있다.

 

 

 위 그림을 보면 한 어플리케이션이 여러 모듈로 분해된 모습을 보여준다.

각 모듈들은 각자 자기가 맡은 서비스 제공을 위하여 사용되지만 이 모듈들은 모두 보안과 트랜젝션관리 같은 보조기능을 필요로 한다.

 

공통기능을 재사용하는 상속같은 개념도 있지만 상속은 객체의 정적구조에 의존하기 쉽기때문에 복잡하고 깨지기 쉬운 구조로 되어있다.

 

물론 AOP도 공통적으로 한 곳에 공통기능을 정의한다는 것은 같다.

 

하지만 이 기능을 어디에 어떻게 적용할 지 선언할 수 있고 대상 클래스를 전혀 수정할 필요가 없다는 것이 가장 큰 차이점이다.

 

정리하자면 AOP는 이러한 횡단관심사의 분리를 위하여 나왔으며, 횡단관심사의 모듈화를 하기 위하여 AOP라는 개념이 등장하였다.

 

2. AOP의 개념

 

기능을 핵심 비지니스 로직과 공통모듈로 구분하고, 핵심 로직에 영향을 미치지 않고 사이사이에 공통 모듈을 효과적으로 잘 끼어넣도록 하는 개발 방법이다.

 

공통모듈(보안, 인증, 로깅 같은 요소 등)을 만든 후에 코드 밖에서 이 모듈을 비즈니스 로직에 삽입하는 것이 바로 AOP적인 개발이다.

 

 

 Aspect 지향 프로그래밍

 

 횡단관심사를 모듈화 할 때 특별한 클래스로 모듈화 하는데 그 특별한 클래스가 바로 Aspect 라고 부른다.

 

3. AOP 가 사용되는 경우

 

a. 간단한 메소드 성능 검사

-. 개발 도중 DB에 대량의 데이터를 처리할때 작업시간에 대하여 시간을 측정해보고 쿼리를 개선하는 작업은 매우 의미가 있다. 메소드 처음과 끝에 System.currentTimeMills()를 사용하거나, stopWatch코드를 사용하기에는 번거로움이 있다.

 

b. 트랜젝션 처리

-. 트렌젝션의 경우 비즈니스 로직의 전후에 설정된다. 하지만 매번 사용하는 트랜젝션(try~catch)의 코드는 번거롭고, 소스를 더욱 복잡하게 보여준다.

 

c. 예외 반환

-. 스프링에는 DataAccessException 이라는 매우 잘 정의되어있는 예외 계층구조가 있다. 예전 하이버네이트 예외들은 몇개 없었고 그나마도 UncatchedException 이 아니었다. 이렇게 구조가 별로 안좋은 예외들이 발생했을 때, 그걸 잡아서 잘 정의되어있는 예외 계층 구조로 변환해서 다시 던지는 Aspect는 제 3의 프레임워크를 사용할 때, 본인의 프레임워크나 어플리케이션에서 별도의 예외 계층구조로 변환하고 싶을 때 유용하다.

 

d. 아키텍처 검증

 

e. 기타

-. Hibernate와 JDBC를 같이 사용할 경우, DB동기화 문제 해결

-. MultiThread Safety 관련하여 작업해야 하는 경우, 메소드들의 일괄적으로 락을 설정하는 Aspect

-. 데드락 등으로 인한 PessimisticLockingFailureException 등의 예외를 만났을 때 재시도하는 Aspect

-. 로깅, 인증, 권한 등

 

4. AOP의 용어

 

Aspect 를 이해하기 위해서는 우리가 이해해야할 용어들이 몇 개 존재한다.

 

AOP에서 가장 중요한 용어는 어드바이스(Advice), 포인트 컷(Point Cut), 조인 포인트(Join Point)이 3가지이다.

 

 

 

 

a. 조인포인트(Join Point) - 횡단 관심 모듈의 기능이 삽입되어 동작할 수 있는 실행 가능한 특정위치

어플리케이션 하나에도 어드바이스를 적용할 수 있는 곳이 무수히 많으며 적용할 수 있는 곳을 조인포인트라고 말한다.

즉 조인포인트는 어플리케이션 실행에 Aspect 를 끼워 넣을 수 있는 지점이며 이러한 조인포인트 지점은 메소드 호출지점이나 예외발생, 필드값 수정 등 있다.

 

ex) 메소드가 호출되는 부분 또는 리턴되는 시점, 필드를 엑세스하는 부분, 인스턴스가 만들어지는 지점, 예외가 던져지는 시점, 예외 핸들러가 동작하는 위치, 클래스가 초기화되는 곳 등이 대표적인 조인포인트가 될 수 있다. 각각의 조인포인트들은 그 안에 횡단관심의 기능이 AOP에 의해 자동으로 추가되어져서 동작할 수 있는 후보지가 되는 것이다.

 

b. 포인트 컷(Point Cut) - 어떤 클래스의 어느 조인포인트를 사용할 것인지를 결정하는 선택 기능

한 Aspect가 전체 어플리케이션의 모든 조인포인트를 다 어드바이스 할 수 없다. 이 때문에 포인트 컷은 Aspect가 어드바이스할 조인포인트의 영역을 좁혀주는 역할을 한다.

 

어드바이스가 Aspect 가 무엇을 언제할지 정의한다면 포인트 컷은 어디서를 정의하는 역할을 한다고 보면 된다.

 

포인트 컷을 지정하는 방법은 클래스나 메소드 명을 직접 사용하는 것이지만 정규표현식으로 정의하는 방법도 있다.

 

AOP에서는 포인트컷을 수행할 수 있는 다양한 접근 방법을 제공한다. Aspect 에서는 와일드카드를 이용한 메소드 시그니처를 사용한다.

 

c. 어드바이스(Advice) - Advice 또느 Interceptor

 

어드바이스(Advice) : 각 조인포인트에 삽입되어져 동작할 수도 있는 코드

-. 주로 메소드 단위로 구성된 어드바이스는 포인트컷에 의해 결정된 모듈의 조인포인트에서 호출되어 사용된다.

-. 일반적으로 독립적인 클래스 등으로 구현된 횡단 관심 모듈을 조인포인트의 정보를 참조해서 이용하는 방식으로 작성된다.

 

인터셉터 : 인터셉터 체인 방식의 AOP 툴에서 사용하는 용어로 주로 한개의 invoke 메소드를 가지는 어드바이스

 

Aspect 는 자신이 무엇을 해야할 지를 알고 있어야 한다.

이때 Aspect 가 해야할 작업을 AOP용어로 어드바이스(Advice) 라고 한다.

 

어드바이스는 Aspect 가 해야하는 작업에 대하여 언제 그 작업을 수행해야하는지 정의를 해준다.

어드바이스가 정의하는 언제는 메소드가 호출 이전인지 이후인지, 아니면 이전/이후 모두인지 그것도 아니면 예외를 던졌을 때인지를 의미한다.

 

그 언제를 표현하기 위해서는 아래와 같은 선언방식을 사용한다.

 

 * 이전(Before) : 어드바이스 대상 메소드가 호출되기 전에 어드바이스 기능을 수행한다.

 * 이후(After) : 결과에 상관없이 어드바이스 대상 메소드가 완료된 후에 어드바이스 기능을 수행한다.
 * 반환 이 후(after-returning) : 어드바이스 대상 메소드가 성공적으로 완료된 후에 어드바이스 기능을 수행한다.

 * 예외 발생 이후(after-throwing) : 어드바이스 대상 메소드가 예외를 던진 후에 어드바이스 기능을 수행한다.

 * 주의(arount) : 어드바이스가 어드바이스 대상메소드를 감싸서 어드바이스 대상 메소드 호출전 과 후에 몇가지 기능을 제공한다. 

d. 인트로덕션(Introduction) - 인트로덕션(Introduction) 또는 인터타입 선언

인트로덕션 - 정적인 방식의 AOP 기술

 

인트로덕션을 앞서 설명했던 AOP 장점 중 기존 클래스에 코드 변경없이 새 메소드나 맴버 변수를 추가하는 기능이다.

 

동적인 AOP 방식을 사용하면 코드의 조인포인트에 어드바이스를 적용해서 핵심관심 코드의 동작 방식을 변경할 수 있다.

인트로덕션은 이에 반해서 기존의 클래스와 인터페이스에 필요한 메소드나 필드를 추가해서 사용할 수 있게 해주는 방법

AOP에서 말하는 오브젝트 상속이나 확장과는 다른 방식으로 어드바이스 또는 ASpect를 이용해서 기존 클래스에 없는 인터페이스 등을 다이내믹하게 구현해 줄 수 있다.

 

예를 들어 "어떤 객체의 상태가 언제 마지막으로 변경되었다" 라는 정보는 추가하는 경우를 생각해보자.

각 클래스마다 해당 정보를 저장하는 대신, auditable 어드바이스 클래스를 생성하여 setLastModified(Date) 메소드와 이 상태를 저장하는 맴버 변수를 정의한다. 그 다음 인트로덕션을 적용하면 기존 클래스에 소스코드 변경없이 새로운 메소드와 맴버변수를 사용할 수 있다.

 

e. 에스팩트(Aspect) - 에스펙트(Aspect) 또는 어드바이스(Advice)

Aspect는 어드바이스와 포인트 컷을 합친 것이다.

두가지 정보가 합쳐지면 무엇을(Advice) 어디에서할지에(Point Cut) 대한 모든 정보가 정의된다. (필요에 따라 인트로덕션도 포함)

 

f. 위빙(Weaving) - 위빙(Weaving) 또는 크로스컷팅(Cross Cutting)

위빙 - 포인트컷에 의해서 결정된 조인포인트에 지정된 어드바이스를 삽입하는 과정(다른 말로 크로스커팅)

어드바이스를 핵심코드 로직에 적용하는 것을 위빙(Weaving)이라고 한다.

 

위빙은 AOP가 기존의 핵심 관심 모듈의 코드에 전혀 영향을 주지 않으면서 필요한 횡단 관심기능을 추가할 수 있게 해주는 핵심 처리과정이다.

 

어드바이스를 위빙하는 방식은 3가지 방식이 존재한다.

 

  * 컴파일 시에 위빙하기

 

 컴파일 시 코드를 삽입하는 방법은 aspectJ에서 사용하는 방식이다.

 컴파일 방식에서는 핵심 로직을 구현한 자바 코드를 컴파일 할 때 알맞은 위치에 공통코드를 삽입한다.

 공통코드는 횡단관심사를 모듈화한 코드를 말한다.

 

 이렇게 컴파일된 코드는 AOP가 적용된 클래스 파일이 생성된다.

 컴파일 방식을 제공하는 AOP 도구는 공통코드를 알맞은 위치에 삽입할 수 있도록 도와주는 컴파일러나 IDE를 제공함

 

 * 클래스 로딩시에 위빙하기

 

 AOP 라이브러리는 JVM이 클래스를 로딩할 때 클래스 정보를 변경할 수 있는 에이전트를 제공한다.

 이 에이전트는 로딩한 클래스의 바이너리 정보를 변경하여 알맞은 위치에 공통 코드를 삽입한 새로운 바이너리 코드 를 사용하도록 한다.

 

 * 런타임 시에 위빙하기<제일 중요 : 스프링은 자체적으로 프록시 기반의 AOP를 지원하고 있음>

 

 런타임시 AOP를 적용할 때는 소스코드나 클래스 정보 자체를 변경하지 않는다. 대신 프록시를 이용하여 AOP를 적용한다.

 프록시 기반의 AOP는 핵심로직을 구현한 객체에 직접 접근하는 것이 아니라 중간에 프록시를 생성하여 프록시를 통해 핵심로직을 구현한 객체에 접근하게 된다.

 

 이때, 프록시는 핵심 로직을 실행하기 전 또는 후에 공통기능을 적요하는 방식으로 AOP를 적용하게 된다.

 프록시 기반에서는 메소드가 호출될 때에만 어드바이스를 적용할 수 있기 때문에 필드값 변경과 같은 조인 포인트에 대해서는 적용할 수 없는 한계가 있다.

 

g. Primary(Core) Concern - 비지니스 로직을 구현한 부분

h. Cross-Cutting Concern - 보안, 인증, 로그 등과 같은 부가적인 기능으로서 시스템 전반에 산재되어 사용되는 기능

i. Code - Primary(Core) Concern 을 구현해 놓은 코드를 이야기

 

5. Spring 에서의 AOP 특징

a. 스프링은 자체적으로 프록시 기반의 AOP를 지원하고 있다.

b. 스프링 AOP는 자바기반이다.