스프링 AOP

2020. 5. 3. 21:06인프런/스프링 입문

AOP

AOP는 Aspect Oriented Programming의 약자로 관점 지향 프로그래밍이라고 불립니다 관점 지향을 쉽게 어떤 로직을 기준으로 핵심적인 관점 부가적인 관점으로 나누어서 보고 그 관점을 기준으로 각각 모듈화하는것 입니다. 여기서 모듈화란 어떤 공통된 로직이나 기능을 하나의 단위로 묶는 것을 말합니다.

 

예로들어 핵심적인 관점은 결국 우리가 적용하고자 하는 핵심 비즈니스 로직이 됩니다 또한 부가적인 관점은 핵심 로직을 실행하기 위해서 행해지는 데이터베이스 연결,로깅,파일 입출력 들을 예로 들 수 있습니다.

 

AOP에서 각 관점을 기준으로 로직을 모듈화한다는 것은 코드들을 부분적으로 나누어서 모듈화하겠다는 의미다. 이때, 소스 코드상에서 다른 부분에 계속 반복해서 쓰는 코드들을 발견할 수 있는 데 이것을 흩어진 관심사 (Crosscutting Concerns)라고 부릅니다 

위의 사진처럼 흩어진 관심사를 Aspect로 모듈화하고 핵심적인 비즈니스 로직에서 분리하여 재사용하겠다는 것이 AOP취지 입니다

Aspect란?

애스펙트는 부가기능을 정의한 코드인 어드바이스(Advice)와 어드바이스를 어디에 적용하지를 결정하는 포인트컷(PointCut)을 합친 개념입니다

 

Advice + PointCut = Aspect

 

AOP 개념을 적용하면 핵심기능 코드 사이에 침투된 부가기능을 독립적인 애스펙트로 구분해 낼수 있습니다. 구분된 부가기능 애스펙트를 런타임 시에 필요한 위치에 동적으로 참여하게 할 수 있습니다.

 

AOP 주요 용어

  • 타겟(Target)
     핵심 기능을 담고 있는 모듈로 타겟은 부가기능을 부여할 대상이 됩니다.
  • 어드바이스(Advice)
    어드바이스는 타겟에 제공할 부가기능을 담고 있는 모듈입니다.
  • 조인포인트(Join Point)
    어드바이스가 적용될 수 있는 위치를 말합니다.
    타겟 객체가 구현한 인터페이스의 모든 메서드는 조인 포인트가 됩니다.
  • 포인트 컷(Pointcut)
    어드바이스를 적용할 타겟의 메서드를 선별하는 정규표현식 입니다.
    포인트컷 표현식은 execution으로 시작하고 메서드의 Signature를 비교하는 방법을 주로 이용합니다.
  • 애스펙트(Aspect)
    애스펙트는 AOP의 기본 모듈입니다.
    애스펙트 = 어드바이스 + 포인트컷
    애스펙트는 싱글톤 형태의 객체로 존재합니다.
  • 어드바이저(Advisor)
    어드바이저 = 어드바이스 + 포인트컷
    어드바이저는 Spring AOP에서만 사용되는 특별한 용어입니다.
  • 위빙(Weaving)
    위빙은 포인트컷에 의해서 결정된 타겟의 조인 포인트에 부가기능(어드바이스)를 삽입하는 과정을 뜻합니다.
    위빙은 AOP가 핵심기능(타겟)의 코드에 영향을 주지 않으면서 필요한 부가기능(어드바이스)를 추가할 수 있도록 해주는 핵심적인 처리과정입니다.

 

스프링 AOP 특징

  • 프록시 패턴 기반의 AOP 구현체, 프록시 객체를 쓰는 이유는 접근 제어 및 부가기능을 추가하기 위해서임
  • 스프링 빈에만 AOP를 적용 가능
  • 모든 AOP 기능을 제공하는 것이 아닌 스프링 IoC와 연동하여 엔터프라이즈 애플리케이션에서 가장 흔한 문제(중복코드, 프록시 클래스 작성의 번거로움, 객체들 간 관계 복잡도 증가 ...)에 대한 해결책을 지원하는 것이 목적

 

XML기반의 AOP 구현

의존설정

스프링 @AOP를 사용하기 위해서는 다음과 같은 의존성을 추가해야 합니다.

<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjweaver</artifactId>
	<version>1.7.4</version>
</dependency>

공통기능의 클래스 제작 - Advice 역할 클래스

public class LogAop {

public Object loggerAop(ProceedingJoinPoint joinPoint) throws Throwable {

   }
   
}

XML설정 파일에 Aspect 설정

<bean id="logAop" class="com.edu.ex.LogAop"></bean>
<aop:config>
	<aop:aspect id="logger" ref="logAop">
	<aop:pointcut expression="within(com.edu.ex.*)" id="publicMethod"/>
	<aop:around pointcut-ref="publicMethod" method="loggerAop"/>
    </aop:aspect>
</aop:config>

 

@Around 외에 타겟 메서드의 Aspect 실행 시점을 지정할 수 있는 어노테이션이 있습니다. 

  • @Before (이전) : 어드바이스 타겟 메소드가 호출되기 전에 어드바이스 기능을 수행
  • @After (이후) : 타겟 메소드의 결과에 관계없이(즉 성공, 예외 관계없이) 타겟 메소드가 완료 되면 어드바이스 기능을 수행
  • @AfterReturning (정상적 반환 이후)타겟 메소드가 성공적으로 결과값을 반환 후에 어드바이스 기능을 수행
  • @AfterThrowing (예외 발생 이후) : 타겟 메소드가 수행 중 예외를 던지게 되면 어드바이스 기능을 수행
  • @Around (메소드 실행 전후) : 어드바이스가 타겟 메소드를 감싸서 타겟 메소드 호출전과 후에 어드바이스 기능을 수행

AOP 프록시(AOP Proxy)

: 스프링프레임워크에서 실질적으로 AOP를 적용하여 사용하는 기술

프록시(Proxy)

클라이언트가 사용하려고 하는 실제 대상인 것처럼 위장 하여 클라이언트의 요청을 받고 대리하여 업무를 처리하는 대리자 역활입니다 함수호출자는 주요 없무가 아닌 보조업무를 프록시에게 맡기고 프록시는 내부적으로 보조 업무를 처리합니다 이렇게 함으로써 주 업무코드는 필요에 따라 보조업무를 처리하는 해당 Proxy만 추가및 제거하면됩니다

보조 업무의 탈부찰이 쉬워지고 그리하여 주 업무 코드는 보조업무코드의 변경으로 인해서 발생하는 코드수정작업이 필요 없게됩니다.

마지막으로 프록시의 사용 목적은 클라이언트가 타깃(Target)에 접근하는 방법을 제어하며 타깃에 부가적인 기능을 부여합니다.

프록시를 이용한 AOP 구현

스프링은 프록시를 이용하여 AOP를 구현합니다. 스프링은 Aspect의 적용대상이 되는 객체에 대한 프록시를 만들어 제공합니다. 비지니스 로직에 접근할 때 대상 객체로 바로 접근하는 게 아닌 프록시를 통해서 간접적으로 접근하게 됩니다. 이 과정에서 프록시는 공통 기능을 실행한 뒤 대상 객체의 실제 메서드를 호출하거나 또는 대상객체의 실제 메소드를 호출한 후에 공통기능을 실행합니다.

대상 타겟은 결국 빈 객체가 생성 되는데, 런타임시에 오브젝트 생성 설정에 따라서 스프링 컨테이너가 지정한 빈 객체 대한 프록시 객체를 생성하고, 원본 빈 객체 대신에 프록시 객체를 사용하게 합니다.

프록시 객체를 생성하는 방식은 대상 객체가 인터페이스를 구현하고 있느냐 없느냐 여부에 따라 달라집니다. 2가지 방식이 존재하는데 JDK Dynamic Proxy, CGLIB를 이용하여 프록시를 생성하는 방식이 있습니다.

JDK Dynamic Proxy

스프링은 자바 리플렉션 API가 제공하는 java.lang.reflect.Proxy를 이용하여 프록시 객체를 생성합니다. 아래 그림과 NConnectionMaker,DConnectionMaker와 같이 동일한 인터페이스를 구현하게되면 UserDao와 같은 클라이언트는 인터페이스를 통해서 필요한 메서드를 호출하게 됩니다. 하지만, 인터페이스를 기반으로 프록시 객체를 생성하기 때문에 인터페이스에 정의되어 있지 않은 메서드에 대해서는 AOP가 적용되지 않는 점에 유의해야합니다.

CGLIB

대상객체가 인터페이스를 구현하고 있지 않고 바로 클래스를 사용한다면, 스프링은 CGLIB를 이용하여 클래스에 대한 프록시 객체를 생성합니다.  CGLIB는 대상 클래스를 상속 받아 프록시를 구현합니다. 따라서 클래스가 final인경우에는 프록시를 생성할 수 없습니다.

 

강제로 CGLIB를 이용하여 Proxy를 생성하는 방법

@EnableAspectJAutoProxy 어노테이션 속성으로 proxyTaretClass란 것이 있습니다. 위에서 말한대로 Spirng AOP는 Proxy class를 생성함으로 AOP를 구현 합니다. AOP의 대상이 되는 클래스가 Interface를 구현하고 있을 경우 Spring은 Interface를 이용하는 JDK Dynamic Proxy를 만들어서 AOP를 구현하고 Interface를 구현하지 않고 클래스에 대해서는 CG-LIB를 이용한 대상클래스의 상속을받아 서브클래스를 만들어 이를 Proxy삼아 AOP 구현하게 됩니다. 이 속성 값을 주지 않으면 기본값은 false이기 때문에 대상이 되는 클래스가 interface를 이용한것은 자동으로 JDK Dynamic Proxy를 이용해서 AOP를 생성하고 아닌경우에는 CG-LIB를 이용해 클래스 Proxy로 AOP를 구현하게 됩니다. 이 속성을 true로 주게되면 인터페이스 또한 CG-LIB를 이용하여 서브클래스 생성하는 방식으로 AOP의 프록시를 구현하게 됩니다.

'인프런 > 스프링 입문' 카테고리의 다른 글

스프링PSA  (0) 2020.05.04
스프링IOC  (0) 2020.05.02
스프링  (0) 2020.05.01