Study/Spring

[Spring] 스프링 핵심 원리 - 스프링 AOP

sw_develop 2025. 4. 23. 21:45

AOP 소개 - 핵심 기능과 부가 기능

  • 어플리케이션 로직은 크게 핵심 기능과 부가 기능으로 나눌 수 있음
    • 핵심 기능 : 해당 객체가 제공하는 고유의 기능
    • 부가 기능 : 핵심 기능을 보조하기 위해 제공되는 기능 ex) 로그 추적 로직, 트랜잭션 기능
      • 단독으로 사용되지 않고, 핵심 기능과 함께 사용됨
  • 부가 기능 적용 문제
    • 보통 부가 기능은 여러 클래스에 걸쳐서 함께 사용됨. 따라서 이러한 부가 기능은 횡단 관심사(cross-cutting concerns)가 됨
      • 즉, 하나의 부가 기능이 여러 곳에 동일하게 사용되다는 뜻
    • 아래와 같은 문제 발생
      • 부가 기능이 여러 곳에 퍼져 중복 코드를 만들어냄
      • 중복으로 인해 부가 기능을 변경하거나 부가 기능의 적용 대상을 변경할 때 많은 수정이 필요함

 

AOP 소개 - Aspect

  • 위와 같은 부가 기능의 문제를 보완하기 위해 Aspect라는 개념을 도입
    • 부가 기능과 부가 기능을 어디에 적용할지 선택하는 기능을 합해서 하나의 모듈로 만듦
    • Aspect는 부가 기능과, 해당 부가 기능을 어디에 적용할지 정의한 것
    • 스프링이 제공하는 Advisor도 Advice(부가 기능)와 Pointcut(적용 대상)을 가지고 있어서 개념상 하나의 Aspect임
  • Aspect는 '관점'이라는 뜻으로, 이름 그대로 어플리케이션을 바라보는 관점을 하나하나의 기능에서 횡단 관심사(cross-cutting concerns) 관점으로 달리 보는 것
  • Aspect를 사용한 프로그래밍 방식을 '관점 지향 프로그래밍 AOP(Aspect-Oriented Programming)'이라 함
    • 횡단 관심사를 깔끔하게 처리하기 어려운 OOP의 부족한 부분을 보조하는 목적으로 개발됨
  • AOP의 대표적인 구현으로 AspectJ 프레임워크가 있음
    • 스프링도 AOP를 지원하지만 대부분 AspectJ의 문법을 차용하고, AspectJ가 제공하는 기능의 일부만 제공함

 

AOP 적용 방식

스프링런타임 시점에 프록시 방식의 AOP 를 사용

  • 런타임 시점컴파일과 클래스 로딩이 끝나서 이미 자바가 실행되고 난 다음을 말함
    • 즉, 자바의 메인(main) 메서드가 이미 실행된 후
  • 따라서 자바 언어가 제공하는 범위 안에서 부가 기능을 적용해야 함
    • 스프링과 같은 컨테이너의 도움을 받고, 프록시과 DI, Bean Post Processor 같은 기능들을 동원해야 함
  • 최종적으로 프록시를 통해 스프링 빈에 부가 기능을 적용할 수 있음
  • 참고)
    • 스프링은 AspectJ의 문법을 차용하고 프록시 방식의 AOP를 적용함. AspectJ를 직접 사용하는 것이 아님

 

프록시 방식을 사용하는 스프링 AOP의 장단점

  • 장점
    • 특별한 컴파일러나, 자바를 실행할 때 복잡한 옵션과 클래스 로더 조작기를 설정하지 않아도 됨
    • 스프링만 있으면 얼마든지 AOP를 적용할 수 있음
  • 단점
    • AOP 기능에 일부 제약이 있음
      • 메서드 실행 지점에만 AOP를 적용할 수 있음
        • 프록시는 메서드 오버라이딩 개념으로 동작함. 따라서 생성자나 static 메서드, 필드 값 접근에는 프록시 개념이 적용될 수 없음
        • 즉, 스프링 AOP의 조인 포인트는 메서드 실행으로 제한됨
      • 스프링 컨테이너가 관리할 수 있는 스프링 빈에만 AOP를 적용할 수 있음
        • BeanPostProcessor를 사용해 프록시 객체를 스프링 빈으로 등록하기 때문
        • 대상 객체가 스프링 빈이 아니라면 프록시 객체를 런타임에 생성하지 않음

 

정리하면,

  • 스프링이 제공하는 AOP는 프록시를 사용
  • (스프링 빈을 대상으로) 프록시를 통해 메서드를 실행하는 시점에만 AOP가 적용
  • 스프링 AOP는 별도의 추가 자바 설정 없이 스프링만 있으면 편리하게 AOP를 사용할 수 있음

 

추가) 컴파일 시점, 클래스 로딩 시점의 AOP 적용 방식

더보기

컴파일 시점

  • .java 소스 코드를 컴파일러를 사용해 .class를 만드는 시점에 부가 기능 로직을 추가
  • AspectJ가 제공하는 특별한 컴파일러를 사용해야 함
  • 컴파일된 .class를 디컴파일 해보면 Aspect 관련 호출 코드가 들어가 있음
  • AspectJ 컴파일러는 Aspect를 확인해 해당 클래스가 적용 대상인지 먼저 확인하고, 적용 대상인 경우에 부가 기능 로직을 적용함
  • 이렇게 원본 로직에 부가 기능 로직이 추가되는 것을 '위빙(Weaving)'이라 함

 

단점

  • 컴파일 시점에 부가 기능을 적용하려면 특별한 컴파일러도 필요하고 복잡함

 

클래스 로딩 시점

  • 자바를 실행하기 위해 클래스 파일을 JVM의 런타임 데이터 영역에 로딩
  • 이때 중간에서 .class 파일을 조작한 다음 JVM에 올릴 수 있음
  • 자바 언어는 .class를 JVM에 로딩하기 전에 조작할 수 있는 기능을 제공함
  • 이 시점에 Aspect를 적용하는 것을 '로드 타임 위빙'이라 함

 

단점

  • 자바를 실행할 때 특별한 옵션(java -javaagnet)을 통해 클래스 로더 조작기를 지정해야 하는데, 이 부분이 번거롭고 운영하기 어려움

 

런타임 시점에 적용하는 AOP와의 차이

  • 부가 기능 적용 차이
    • 컴파일 시점, 클래스 로딩 시점에 적용하는 AOP
      • 실제 대상 코드에 Aspect를 통한 부가 기능 호출 코드가 포함됨
      • AspectJ를 직접 사용해야 함
    • 런타임 시점에 적용하는 AOP
      • 실제 대상 코드는 그대로 유지됨. 대신 프록시를 통해 부가 기능이 적용됨
      • 따라서 항상 프록시를 통해야 부가 기능을 사용할 수 있음
  • AOP 적용 위치
    • 컴파일 시점, 클래스 로딩 시점에 적용하는 AOP
      • AspectJ를 사용해 바이트코드를 실제 조작하기 때문에 모든 지점에 적용할 수 있음
        • 적용 가능 지점(join point) : 생성자, 필드 값, static 메서드, 메서드
    • 런타임 시점에 적용하는 AOP
      • 프록시 방식을 사용하기 때문에 메서드 실행 지점에만 적용할 수 있음 (메서드 오버라이딩 불가능한 static 메서드 제외)

 

AOP 용어 정리

더보기
  • Join Point
    • Advice가 적용될 수 있는 위치, 메서드 실행, 생성자 호출, 필드 값 접근, static 메서드 접근 같은 프로그램 실행 중 지점
    • 추상적인 개념으로, AOP를 적용할 수 있는 모든 지점을 의미함
    • 스프링 AOP는 프록시 방식을 사용하므로 Join Point는 항상 메서드 실행 지점으로 제한
  • Pointcut
    • Join Point 중에서 Advice가 적용될 위치를 선별함
    • 주로 AspectJ 표현식을 사용해 지정함
    • 프록시를 사용하는 스프링 AOP는 메서드 실행 지점만 Pointcut으로 선별 가능
  • Target
    • Advice를 받는 객체, Pointcut으로 결정됨
  • Advice
    • 부가 기능
    • Around, Before, After와 같은 다양한 종류의 Advice가 있음
  • Aspect
    • Advice + Pointcut을 모듈화한 것
    • @Aspect를 생각하면 됨
    • 여러 Advice와 Pointcut이 함께 존재함
  • Advisor
    • 하나의 Advice와 하나의 Pointcut으로 구성
    • 스프링 AOP에서만 사용되는 특별한 용어
  • Weaving
    • Pointcut으로 결정한 Target의 Join Point에 Advice를 적용하는 것
    • 핵심 기능 코드에 영향을 주지 않고 부가 기능을 추가할 수 있음
  • AOP 프록시
    • AOP 기능을 구현하기 위해 만든 프록시 객체
    • 스프링에서 AOP 프록시는 JDK 동적 프록시 또는 CGLIB 프록시