Home Spring AOP(1)
Post
Cancel

Spring AOP(1)

AOP

AOP는 Aspect Oriented Programming의 약자로 관점 지향 프로그래밍을 뜻합니다. AOP는 시스템을 구성하고 모듈화하는 새로운 방법을 제공하는 프로그래밍 방법론으로 OOP(Object Oriented Programming)의 보완적인 개념으로 등장했습니다. OOP는 주로 주요 비즈니스 로직을 객체로 추상화하여 모델링하는데 중점을 두기 때문에 중복되는 관심사(Concerns) 문제를 해결하기에는 제한적입니다.

AOP는 이러한 OOP의 한계를 극복하기 위해 등장한 개념으로 Cross-cutting Concerns와 Core Concerns를 분리하여 모듈화하는 것을 목표로 합니다.
관심사를 Aspect 라는 모듈로 모델링하여 주요 비즈니스 로직과는 별개로 존재하면서도 여러 모듈에 걸쳐 적용되는 보조 기능을 담당합니다.

Cross-cutting Concerns

cross-cutting-concerns

출처

AOP는 객체를 핵심 관심사(Core Concerns)와 횡단 관심사(Cross-cutting Concerns)로 구분하고 분리합니다. 핵심 관심사는 각 객체가 가지고 있는 주요 비즈니스 로직이나 주된 기능을 의미합니다. 반면에 횡단 관심사는 주요 비즈니스 로직과는 독립적으로 여러 부분에 걸쳐서 반복적으로 발생하는 부가적인 기능을 의미합니다. 예를 들어 로깅, 보안, 트랜잭션 관리 등은 횡단 관심사에 해당합니다.

용어

  • Aspect: 횡단 관심사를 모듈화한 것으로 로깅, 보안, 트랜잭션 관리와 같은 보조 기능을 담고 있는 모듈입니다. Aspect는 Advice와 Pointcut으로 구성됩니다.
  • Joinpoint: 프로그램 실행 중에 Aspect가 적용될 수 있는 특정 시점을 가리킵니다. 메소드 호출, 객체 생성, 필드 접근 등이 결합점에 해당합니다.
  • Advice: Aspect의 동작을 정의한 부분으로 횡단 관심사를 어떻게 실행할지를 정의합니다.
  • Pointcut: 어떤 Joinpoint가 Aspect의 Advice에 적용될지를 결정합니다. 또한 Pointcut 표현식을 통해 특정 메소드 호출 패턴이나 클래스 등 좀 더 자세한 적용 대상을 지정할 수 있습니다.
  • Weaving: 컴파일 시점, 클래스 로딩 시점, 실행 시점 등에서 Aspect의 코드를 원래 코드에 ‘직접’ 또는 ‘간접’으로 삽입하여 횡단 관심사를 적용합니다.
  • Target Object: 하나 이상의 Aspect의 대상의 Advise 대상이 되는 객체를 뜻하며 Advised Object라고도 합니다. Spring AOP는 런타임 프록시를 사용하여 구현되기 때문에 이 객체는 항상 프록시된 객체 입니다.
  • AOP Proxy: AOP 프레임워크가 Aspect(Advise 메소드 실행 등)을 구현하기 위해 생성한 객체로 Spring Framework에서 AOP Proxy는 JDK Dynamic Proxy 또는 CGLIB Proxy입니다.

Spring AOP

Spring AOP는 순수한 Java로 구현됩니다. 특별한 컴파일 과정이 필요하지 않으며 클래스 로더 계층을 제어할 필요가 없으므로 서블릿 컨테이너 또는 애플리케이션 서버에서 사용하기에 적합합니다. Spring AOP는 완벽한 AOP 구현을 목적으로하는 것이 아닌 AOP와 Spring IoC 간의 긴밀한 통합을 제공하여 애플리케이션의 일반적인 문제를 해결하는데 그 목적을 두고 있습니다.

또한 Spring AOP는 프록시 기반의 AOP 프레임워크입니다. 실제 대상 객체에 대한 접근을 제어하고 중간에서 작업을 수행할 수 있는 중간 계층을 제공하기 위해 Proxy Pattern을 이용하여 AOP를 구현했습니다. 대상 객체에 대한 Aspect를 구현하기 위해 런타임 시점에 프록시를 생성하여 대상 객체를 대체합니다.

또한 AspectJ의 문법을 일부 차용하여 제공합니다. AspectJ의 Pointcut 표현식을 사용하여 Joinpoint를 정의하고 Before, After, Around…와 같은 Adivice 유형을 제공합니다. Spring AOP는 AspectJ의 어노테이션 부분만 차용했을 뿐 컴파일러나 위버에 의존하지 않는 프록시 기반의 프레임워크입니다.

jdk-dynamic-cglib

출처

JDK Dynamic Proxy

JDK Dynamic Proxy는 Java 표준 라이브러리에서 제공되는 동적 프록시 생성 방식으로 Java의 리플렉션 API를 사용하여 동작합니다. 또한 인터페이스를 구현한 클래스에 대해서만 프록시 객체를 생성할 수 있습니다.

Spring AOP는 기본적으로 표준 JDK Dynamic Proxy를 사용합니다. 설정을 통해 CGLIB 프록시도 사용할 수 있는데 이는 대상 객체가 인터페이스가 아닌 클래스에 한정합니다.

출처

CGLIB

CGLIB는 Code Generation Library의 약자로 클래스 바이트 코드 조작하여 프록시를 생성하고 클래스에 대해 프록시 객체를 생성할 수 있도록 해주는 라이브러리입니다. CGLIB는 대상 객체에 포함된 모든 메소드를 재정의하여 프록시를 생성합니다. final 메소드 또는 클래스에 대해 재정의는 할 수 없지만 바이트 코드를 조작하여 프록시를 생성하기 때문에 JDK Dynamic Prxoy보다 상대적으로 성능이 좋습니다.

Spring Boot 기본 Proxy 생성 방식

CGLIB는 내부적으로 다음과 같은 문제점이 있었습니다.

  1. net.sf.cglib.proxy.Enhancer 의존성 주입
  2. Default Construct 필수
  3. CGLib Proxy의 메소드를 호출 시 대상 객체의 생성자가 2번 호출

하지만 Enhancer 의존성 추가 이슈는 Spring 3.2 버전부터 Spring Core 패키지에 포함시킴으로써 더이상 의존성을 추가하지 않아도 사용할 수 있도록 개선 됐습니다. 그 후 스프링 4.0 버전에서는 Objensis 라이브러리의 도움을 받아 [2], [3] 이슈도 개선됐습니다. 결과적으로 CGLIB의 내부적인 모든 문제점들이 개선이 되어 안정화가 됐기 때문에 Spring 4.3, Spring Boot 1.4 버전부터 기본 프록시 메커니즘으로 채택됐습니다.

출처

또한 AspectWerkz, AspectJ, JBoss AOP, Spring AOP, CGLIB … 와 같은 AOP 프레임워크 성능에 대한 밴치마크는 바이트 코드를 조작하는 CGLIB가 Spring AOP(JDK Dynamic Proxy)보다 높은 수치를 나타냅니다.

aop-performance

출처

오탈자 및 오류 내용을 댓글 또는 메일로 알려주시면, 검토 후 조치하겠습니다.