-
[Spring] 스프링 핵심 원리 - 스프링 AOPStudy/Spring 2025. 4. 23. 21:45
AOP 소개 - 핵심 기능과 부가 기능
- 어플리케이션 로직은 크게 핵심 기능과 부가 기능으로 나눌 수 있음
- 핵심 기능 : 해당 객체가 제공하는 고유의 기능
- 부가 기능 : 핵심 기능을 보조하기 위해 제공되는 기능 ex) 로그 추적 로직, 트랜잭션 기능
- 단독으로 사용되지 않고, 핵심 기능과 함께 사용됨
- 부가 기능 적용 문제
- 보통 부가 기능은 여러 클래스에 걸쳐서 함께 사용됨. 따라서 이러한 부가 기능은 횡단 관심사(cross-cutting concerns)가 됨
- 즉, 하나의 부가 기능이 여러 곳에 동일하게 사용되다는 뜻
- 아래와 같은 문제 발생함
- 부가 기능이 여러 곳에 퍼져 중복 코드를 만들어냄
- 중복으로 인해 부가 기능을 변경하거나 부가 기능의 적용 대상을 변경할 때 많은 수정이 필요함
- 보통 부가 기능은 여러 클래스에 걸쳐서 함께 사용됨. 따라서 이러한 부가 기능은 횡단 관심사(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는 별도의 추가 자바 설정 없이 스프링만 있으면 편리하게 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 적용 위치
- 컴파일 시점, 클래스 로딩 시점에 적용하는 AOP
- AspectJ를 사용해 바이트코드를 실제 조작하기 때문에 모든 지점에 적용할 수 있음
- 적용 가능 지점(join point) : 생성자, 필드 값, static 메서드, 메서드
- AspectJ를 사용해 바이트코드를 실제 조작하기 때문에 모든 지점에 적용할 수 있음
- 런타임 시점에 적용하는 AOP
- 프록시 방식을 사용하기 때문에 메서드 실행 지점에만 적용할 수 있음 (메서드 오버라이딩 불가능한 static 메서드 제외)
- 컴파일 시점, 클래스 로딩 시점에 적용하는 AOP
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 프록시임
'Study > Spring' 카테고리의 다른 글
[Spring] 스프링 핵심 원리 - @Aspect AOP (0) 2025.04.22 [Spring] 스프링 핵심 원리 - 빈 후처리기 (0) 2025.04.21 [Spring] 스프링 핵심 원리 - 스프링이 지원하는 프록시 (0) 2025.04.20 [Spring] 스프링 핵심 원리 - 동적 프록시 (0) 2025.04.20 [Spring] 스프링 핵심 원리 - ThreadLocal (1) 2025.04.19 - 어플리케이션 로직은 크게 핵심 기능과 부가 기능으로 나눌 수 있음