Spring

Spring AOP vs AspectJ

ddowulli 2023. 5. 23. 00:58

토비 스프링 책을 공부하다가 Spring의 두번째 핵심인 AOP에 대해 공부 한 것을 다시 이해하고 정리하기 위해 포스팅 해 보았다. 저와 같이 AOP에 대해 공부하고자 하는 분들에게 조금이나마 도움이 됐으면 좋겠다. 

 

Spring AOP란?

  • Aspect Oriented Programmin 의 약자로, 관점 지향 프로그래밍 이라고 부른다.
  • 관점 지향은 애플리케이션 전체 로직을 핵심적인 관점, 부가적인 관점으로 나누어 관점 기준으로 모듈화 하는 것이다.
  • 핵심적인 관점은 업무 로직을 포함하는 기능으로 핵심 기능(Core Concerns)이라 한다.
  • 부가적인 관점은 핵심 기능을 도와주는 기능(데이터베이스 연결, 로깅, 보안 등)을 부가 기능(Cross-cutting Concerns)라 한다.
  • 즉, 관심사의 분리(기능의 분리), 핵심 기능에서 부가 기능을 분리하는 것이다.
  • 분리한 부가 기능을 Aspect라는 모듈형태로 만들어서 설계하고 개발하는 방법이다.
  • Dynamic Proxy나 CGLib처럼 런타임 위빙(Runtime Weaving) 방식의 프록시 패턴으로 동작해 간접적인 방법으로 AOP를 구현하는 것.

*모듈화 : 어떤 공통된 로직이나 기능을 하나의 단위로 묶는 것. 

 

Spring AOP의 핵심기능과 부가기능

위의 그림을 보자.

핵심 기능 중에서 공통된 요소들을 확인 할 수 있을 것이다. OOP에서 바라보던 관점을 다르게 하여 부가기능적인 측면에서 보았을 때 공통된 요소를 추출하자는 것이다. 공통된 부분을 잘라냈다고 하여 AOP에서는 크로스 컷팅(Cross-Cutting)이라고 부르기도 한다. 

 

OOP : 비즈니스 로직의 모듈화, 모듈화의 핵심 단위는 비즈니스 로직

AOP : 인프라 혹은 부가기능의 모듈화, 각각의 모듈들의 주 목적 외의 필요한 부가적인 기능들
(ex. 모니터링 및 로깅, 동기화, 오류 검사 및 처리, 성능 최적화 등)

 

 

Q. 그렇다면 OOP를 적용해도 공통된 기능을 재사용하는 방법도 가능한데 왜 AOP를 적용하는 것일까?

맞다. OOP에서는 공통된 기능을 재사용하는 방법으로 상속을 사용한다.

하지만 전체 애플리케이션에서 여기저기 사용되는 부가기능들은 상속으로 처리하기에는 깔끔한 모듈화가 어렵다.

그래서 그런 어려움을 AOP가 해결해 준다.

부가 기능을 Aspect로 모듈화하고 핵심기능에서 부가기능을 분리함으로써 핵심기능을 설계하고 구현할 때 객체 지향적인 가치를 지킬 수 있도록 도와주는 개념이다. 

 

 

AOP 에서 사용하는 용어 알아보기.

  • Aspect : 공통 관심사(Cross-Cutting Corncern, 부가기능)를 모듈화 한 것. ( advice + pointcut )
  • Target : Aspect(부가기능)를 적용할 핵심 로직을 가진 객체. (클래스, 메서드 등)
  • Advice : Aspect(부가기능)의 동작을 담고 있는 모듈. Aspect의 구현체 (객체의 메서드 조작)
    • JoinPoint
      • Advice가 적용되는 시점(위치)
      • Target 객체가 구현한 인터페이스의 모든 메서드
      • Spring AOP는 프록시 방식으로 사용, 그래서 항상 메서드 실행 시점
        (
        메서드 실행, 생성자 호출, 필드 값 변경같은 특수한 실행 시점)
          return joinPoint.proceed(); 
    • PointCut
      • Advice를 적용할 Target의 메서드를 선별하는 정규 표현식 (Join Point의 정규식)
      • 메서드 실행 시점만 가능. (JoinPoint를 여러개 모아 놓은 것)
      • 표현식은 excution(지정어)으로 시작하고 메서드의 Signature를 비교하는 방법을 주로 이용.
      • 실행 스펙, Pointcut이 일치하는 객체들에게 Aspect 적용(조건문)
           @Pointcut("excution(*hello(..))"
  • Advisor : advice + pointcut 한 쌍을 뜻함.
  • Weaving : pointcut으로 결정한 Target의 JoinPoint에 advice를 적용하는 것.

 

 


 

AspectJ란?

  • Java를 위한(자바 표준) 관점 지향 프로그래밍의 구현체이다.
  • 완전한 AOP 솔루션을 제공하는 것을 목표로 한다.
  • 여러 구현체가 있다.
  • 컴파일 후 위빙(Compile Time Weaving, Post-compile Weaving, Load Time Weaving) 을 지원하여
    컴파일 시점이나 클래스 파일이 로드되는 시점에 바이트코드를 조작하여 위빙하는 방법이다.
  • 코드 기반 스타일과 어노테이션 기반으로 AOP 구현이 가능하다.

 

AspectJ Weaving 유형

  • Compile-time Weaving : 애플리케이션의 소스코드를 입력으로 취하고 출력으로 엮인 클래스 파일을 생성한다.
  • Post-compile Weaving : (컴파일 후 위빙) 바이너리 위빙이라고 한다. 기존 클래스 파일과 JAR파일을 위빙하는데 사용한다. 
  • Load-time Weaving : 클래스 로더가 클래스 파일을 JVM에 로드 할 때까지 위빙이 연기된다는 점이 다르다.

 

AspectJ와 Spring AOP 비교하기

  • 기능과 목표가 다르다.
    • Spring AOP는 간단한 AOP 구현을 제공한다.
      완전한 AOP 솔루션이 아닌 Spring 컨테이너에 의해 관리되는 Bean에서만 적용할 수 있다. 
    • 반면에 AspectJ는 완전한 AOP 솔루션을 제공한다. (독창적인 AOP 기술)
      Spring AOP보다 강력하지만? 훨씬 더 복잡하다.
      모든 도메인 객체에 적용될 수 있다.
  • 성능과 유용성에 따라 서로 다른 유형의 Weaving을 사용한다.
    1. 컴파일 시 Weaving
      • AspectJ에서 지원하는 방식이다.
      • 핵심 로직을 구현한 자바 소스 코드를 컴파일 할 때, 알맞은 위치에 공통 코드를 삽입(weaving)하면
        컴파일 결과(출력) AOP가 적용된 클래스 파일이 생성된다.
      • 컴파일 방식을 제공하는 AOP 도구는 공통 코드를 알맞은 위치에 삽입할 수 있도록 도와주는 컴파일 IDE를 함께 제공한다.
    2. 클래스 로딩 시 Weaving
      • AspectJ에서 지원하는 방식이다. 
      • AOP 라이브러리는 JVM이 클래스를 로딩할 때 클래스 정보를 변경할 수 있는 에이전트를 제공한다.
        이 에이전트는 로딩한 클래스의 바이너리 정보를 변경하여 알맞은 위치에 공통 코드를 삽입한 새로운 클래스 바이너리 코드를 사용하도록 한다.
      • 즉, 원본 클래스 파일은 변경하지 않고 클래스 로딩할 때, JVM이 변경된 바이트 코드를 사용해서 AOP 적용한다.
    3. 런타임 시 Weaving
      • Spring AOP는 프록시를 이용하여 AOP를 적용하며, 런타임 시 위빙을 지원한다.
      • 원본 소스 코드나 클래스 정보 자체를 변경하지 않는 점에서 클래스 로딩 위빙과 유사하지만, 
        클래스 로더가 클래스 파일을 JVM에 로드할 때까지 위빙이 연기된다는 차이점이 있다.
      • 직접 접근이 아닌 중간에 프록시를 생성하여 프록시를 통해 핵심 로직을 구현한 객체에 접근한다.
      • 프록시는 핵심 로직을 실행하기 전/후 에 공통 기능을 적용하는 방식으로 AOP를 구현한다.
  • 내부 구조 및 Application
    • Spring AOP는 프록시 기반 AOP 프레임워크로, 대상 객체에 Aspect를 적용하기 위해선 대상 객체의 프록시를 생성한다. (JDK 동적 Proxy, CGLIB Proxy)
    • AspectJ는 클래스들이 Aspect와 함께 컴파일되기 때문에 런타임 시에는 아무것도 하지 않는다. 
    • 어떤 디자인 패턴도 요구하지 않고 Aspect를 코드에 위빙하기 위해 AspectJ Compiler(ajc)라는 컴파일러를 도입한다. 
    • 이 컴파일러를 통해 프로그램을 컴파일하고 작은 런타임 라이브러리를 추가해 동작한다.
  • JoinPoint
    • Spring AOP는 메서드 실행에만 JoinPoint를 지원한다. (동일 클래스 내 메서드 호출 지원)
    • 동일 클래스 내 다른 메서드 호출 지원하지 않는다. (빈을 분리하거나 AspectJ 사용)
    • AspectJ는 런타임 이전에 실제 코드에 Cross-cutting Concerns(공통관심사)를 위빙한다.
      즉, 모든 Pointcut을 지원한다.
  • 간편성
    • Spring AOP는 구현 시 다른 외장 컴파일러를 필요로 하지 않아 간편하다.
    • AspectJ는 AspectJ compiler(ajc) 컴파일러를 도입해서 모든 라이브러리들을 재 패키징 해야한다.
  • 성능
    • Spring AOP는 애플리케이션 시작 시 생성된 Proxy들을 기반으로 한 프레임워크로 성능에 악영향을 주는 훨씬 적은 수의 메소드만 지원한다.
    • AspectJ는 컴파일 시점 위빙으로 런타임 이전 시점으로 Spring AOP보다 훨씬 빠르다.
    • Aspect를 애플리케이션이 실행되기 전에 위빙하기에 런타임 시 과부하가 없다.

 


[참고 자료]

https://engkimbs.tistory.com/entry/%EC%8A%A4%ED%94%84%EB%A7%81AOP

https://zrr.kr/6GXA