진짜 개발자
본문 바로가기

FrameWork/Spring

Spring - Spring을 왜 사용하나요?(AOP) - 3

728x90
Spring을 왜 사용하나요(AOP)

Spring의 2번째 특징인 AOP에 대한 포스팅입니다. 이제 막 공부하는 것이라 틀린 점이 있다거나 의견이 다른 부분이 있다면 댓글로 남겨주시면 감사드리겠습니다.

 

1. AOP(관점지향 프로그래밍)

1.1 AOP란?

AOPAspect Oriented Programming의 약자로 OOP와 같은 프로그래밍 패러다임의 하나입니다. OOP와 상충되는 의미가 아닙니다. OOP를 돕는 프로그래밍 패러다임입니다. " AOP란 횡단 관심사를 분리함으로써 모듈성을 증가시키는 것이 목적인 프로그램입니다."라고 Wiki에 나와있습니다. 역시 어렵습니다. 그렇다면 횡단 관심사를 분리 시킨다는 것은 무엇일까요?

 

*횡단 관심사?

어플리케이션의 핵심기능은 아니지만, 어플리케이션을 구성하는 중요한 요소임과 동시에 부가적인 기능을 담당하는 것입니다. 예를 들자면 트랜잭션, 로깅, 성능 분석 등이 있습니다.

 

위의 코드에서는 부가기능(Log를 출력하는 코드)이 여러곳에 산재되어있는 것을 볼 수 있습니다.

 

이것을 부가기능의 입장에서 바라본다면 다음과 같이 중복되는 코드를 찾을 수 있습니다. AOP는 기존의 OOP에서 바라보던 관점을 부가기능의 입장에서 보았을 때 공통적인 요소들을 따로 모듈화 하는 것입니다. 다시 말해 코드가 핵심 코드(핵심 관심사)+부가기능(횡단 관심사)로 이루어져 있다고 보았을 때, 반복되는 부가기능핵심코드로 부터 분리하는 것이 AOP의 핵심입니다.

 

 

1.2 AOP가 왜 필요할까?

물론 AOP가 없더라도 프로그래밍은 가능합니다. 하지만 프로그래밍을 하다보면 공통적인 기능이 많이 발생합니다. 가장 간단한 예로 어떤 메소드가 실행되는지를 확인하기 위해 메소드 실행 전후로 Log를 출력하는 등의 기능이 있습니다. 이러한 코드를 계속해서 작성한다면 OOP를 방해하게 됩니다. 따라서 이러한 문제를 해결(횡단 관심사를 코드로 부터 분리)하기 위해서 Spring에서는 AOP를 지원합니다.

 

*OOP를 방해한다?

1. 추상화를 방해

OOP에서는 Car라는 Class가 있을때 Car Class는 Car와 관련된 행위 및 속성만 존재해야하며 해당 Class의 목적과 관련되지 않는 것들은 포함이 되지 않아야 합니다. 위의 코드는 간단히 출발과 정지를 할 수 있는 Car클래스 입니다.

 

이 클래스에 Log를 출력하기 위해서는 다음과 같이 코드가 변경될 것입니다. Log를 출력하는 기능은 Car Class와는 관련이 없지만 Car Class안에 로그를 출력하기 위한 코드를 기술하므로써 해당 객체와 관련이 없는 코드가 추가되어 추상화를 방해하게 됩니다.

 

2. OOP의 목적인 코드의 재사용성과 중복제거를 방해

또한 Log를 출력하는 코드가 계속해서 반복되며 중복을 일으키고, 만약 특정한 조건에 Log를 출력하는 코드가 기입된다면 해당 코드를 재사용하기도 어렵게 될 것입니다.

 

 

*상속을 사용하면 되지 않나요?

상속을 사용한다면 Log 출력 코드를 해당 Class에 넣지 않을 수도 있고 Log 기능이 필요한 Class에서만 상속하여 사용할 수 있지 않을까요? 물론 가능은 할 것입니다. 하지만 Java에서는 다중상속을 지원하지 않기 때문에 좋지 못할 뿐더러, 상속의 목적에 맞지 않습니다. 상속은 어떤 클래스를 확장할 목적을 가지고 있습니다. 따라서 상속을 이용하여 Log를 출력한다면 코드의 가독성을 떨어뜨리고 좋지못한 설계가 될 것입니다.

 

 

1.3 AOP 용어

아래의 용어들은 Spring에 국한된 의미가 아닌 AOP 프레임워크들에서 공통적으로 사용되는 용어들입니다.

1. Target

- 부가기능을 부여할 대상을 의미합니다. 앞선 예제의 Car Class안의 accelerate(), brakeCar()가 해당.

 

2. Aspect

- OOP에서 각 모듈들을 Object(객체)로 부르는 것과 비슷하게 부가기능 모듈Aspect라고 부릅니다. Aspect는 부가 기능을 정의한 AdviceAdvice의 적용 위치를 결정하는 PointCut(포인트 컷)을 포함합니다.

 

3. Advice

- Aspect가 무엇을 언제 할지를 정의하고 있습니다.

- 부가기능을 담은 구현체를 의미합니다.

Advice의 종류

4. JoinPoint

- Advice가 적용될 수 있는 위치를 의미합니다.

- Spring 에서는 메소드 JoinPoint만을 제공합니다.

 

5. PointCut

- 부가기능이 적용될 메소드(어디에)를 선정하는 방법을 의미합니다. 즉 Advice를 적용할 JoinPoint들을 정의한 것입니다.

 

6. Proxy

- 이름에서 알 수 있듯 타켓에대한 요청을 대신 받아 메소드 실행의 전처리, 후처리를 실행합니다.

 

7. Weaving(crossCutting)

- PointCut에 의해서 Joinpoint에 Advice를 삽입하는 과정을 의미합니다.

 

2. Spring AOP 사용법

2.1 Xml 파일을 이용한 AOP

우선 xml을 사용하여 AOP를 사용하는 방법을 알아보겠습니다.

 

우선 AspectJ 라이브러리를 이용하기 위해 pom.xml을 수정해야합니다. 프로젝트안에 포함된 pom.xml을 연뒤 하단의 pom.xml 탭을 클릭합니다. 그 후 maven repository(라이브러리 저장소)에서 얻어온 AspecJ의 의존성을 <dependencies>태그안에 추가합니다.

 

AOP를 적용할 간단한 Class를 생성합니다. Spring에서는 Method에 대해서만 JoinPoint를 제공하기 때문에 accelerate()breakCar()Advice가 적용될 것입니다. 하지만 Aspect J를 이용하면 다양한 곳에 Advice를 추가할 수 있습니다. Aspect J에 대해서는 다음 포스팅에서 알아보겠습니다.

 

그 후 횡단관심사(부가기능)를 정의합니다. 간단하게 메소드의 실행 전후로 print를 하도록 했습니다. 간단하게 분석을 해보자면, logging 메소드의 첫줄에서 인자로 받아온 joinPoint를 이용하여 Method의 이름을 받아오고 있습니다. try문 안의 joinPoint.proceed() 메소드의 경우 핵심관심사를 실행하도록 하는 메소드입니다. 즉, looging메소드는 부가기능을 실행한 뒤 핵심기능을 실행한 뒤 다시 부가기능을 실행하도록 되어있는 형태입니다.


AOP를 설정하기 위해 BeanConfiguration 파일을 생성한뒤 하단의 Namespaces탭으로 이동하여 aop를 체크해줍니다.

 

다시 BeanConfiguration 파일의 Source로 돌아오면 위와 같이 xmlns:aop="http://www.springframework.org/schema/aop"가 추가되었음을 볼 수 있습니다. 우선 앞서 생성한 Class들을 IOC컨테이너가 관리하기 위해 Bean으로 등록을 해줍니다. 그 후 <aop:confg> 태그를 이용하여 aop관련 설정을 진행합니다. 앞서 용어를 살펴보았을때 aspectpointcut과 advice를 포함한다고 했습니다. 따라서 <aop:config> 태그 안에 다시 <aop:aspect>태그를 선언하고 그안에 <aop:pointcut><aop:around>태그(핵심 관심사 전후로 advice를 실행하는 advice)를 추가해 줍니다.

 


호출 결과입니다. car의 메소드는 전혀 수정하지 않고 반복되는 코드인 횡단관심사(부가기능)을 성공적으로 추가했습니다.

 

 

2.2 Annotation(@)을 이용한 AOP

이번에는 Xml을 수정하지 않고 간단하게 Annotation을 부여하여 AOP를 하는방법을 알아보겠습니다. AspectJ를 이용하기 위해 2.1과 같이 pom.xml을 수정하여 AspectJ에 대한 의존성을 추가합니다.

 

그 후 xml 파일로 이동하여 하단의 Namespaces탭을 클릭한 뒤 aopcontext를 체크합니다. context의 경우 scan을 통해 Bean을 등록하기 위함입니다.

 

그후 다시 xml의 source탭으로 돌아와 <aop:aspectj-autoproxy/><context:component-scan base-package="bean으로 등록될 클래스들이 있는 package경로"를 추가합니다.

 

Car class의 경우 코드 변경이 일어나지 않습니다. 다만 편의를 위해 bean을 자동으로 등록하는 @Component Annotation만을 추가했습니다.

 

LogAop Class의 경우 마찬가지로 Bean으로 등록하기 위해 @Component Annotation을 추가했습니다. 이후 @Aspect Annotation을 통해 해당 클래스가 횡단관심사(부가기능)임을 알립니다. 마지막으로 횡단관심사(부가기능) 로써 실행될 Method위에 @Around(Advice)Annotation을 추가합니다. 또한 @Around에는 당연히 PointCut을 포함시켜야 합니다.

 



3. AOP 적용방법

AOP를 적용하는 방법?이 무엇일까요. 우리가 작성한 AOP를 실제 코드에 반영하는 방법을 말합니다. 즉, 각각의 코드들에서 모듈화 시킨 횡단관심사를 원하는 곳에서 실행하도록 개발자가 작성한 것을, 실제 프로그램에서 적용하는 방법을 말합니다. 적용 방법은 크게 아래의 세가지 방법이 존재합니다.

3.1 컴파일 타임 (Aspect J)

 - 성능 부하가 없다

 - 조인 포인트가 다양하다

 - 별도의 컴파일 과정이 필요

3.2 로드 타임 (Java Agent)

3.3 런 타임 (Spring AOP)

 - 프록시 기반의 AOP

 - 스프링 빈에만 AOP를 적용 가능

 


4. AOP 요약

AOP의 중요한 점은 핵심기능의 코드를 변경하지 않고서 부가기능을 실행하도록 한 것입니다. 따라서 핵심코드와, 횡단관심사(부가기능)을 완전히 모듈화 했습니다. 또한 각 횡단 관심사를 모듈화 함으로써 반복되는 코드를 제거 했습니다.