어플리케이션의 로직은 핵심 기능과 부가 기능으로 나뉜다.
여기서 핵심 기능을 해당 객체가 제공하는 고유 기능을
부가 기능은 핵심 기능을 보조하기 위해 제공되는 기능이다.
예를을어 위을 보면 주문 로직이 핵심 기능, 로그 추적 로직이 부가 기능이다.
그런데 이 로그 추적 로직의 타켓이 여러개라면?
이 부가기능이 필요한 모든 타겟을 일일이 수정해줘야하는 문제가 발생한다.
이처럼 여러 곳에서 동일하게 사용되는 부가기능을 횡단관심사라고 한다.
부가 기능 적용시 발생할 수 있는 문제
- 아주 많은 반복
- 여러 곳에 발생하는 중복 코드
- 부가 기능 변경 시 많은 수정 필요
- 부가 기능 적용 대상 변경 시 많은 수정 필요
이러한 문제는 단순히 OOP방식으로는 해결이 어렵다. 따라서 OOP에 더해 이런 문제를 해결할 수 있는 AOP가 등장하게 되었다.
애스펙트
핵심 기능과 부가 기능의 분리
위에서 드러난 문제를 해결하기 위해 부가 기능을 핵심 기능에서 분리해 한 곳에서 관리하고, 해당 부가 기능을 어디에 적용할지 선택할 수 있도록 만들었다.
이처럼 부가 기능과 부가 기능 적용을 선택할 수 있는 기능을 하나의 모듈로 만든 것이 에스팩트(aspect)이다.
에스팩트는 관점이라는 뜻으로 아래의 그림처럼 하나하나의 개별적인 기능 관점에서 보는 것이 아니라 횡단 관심사 관점으로 보는 것을 뜻한다.
AOP는 OOP를 대체하기 위한 목적이 아니라 OOP만으로 부족한 부분을 보조하는 목적으로 개발되었다.
AspectJ 프레임워크
AOP의 대표적인 구현으로 AspectJ프레임워크가 있다.
스프링은 대부분 AspectJ의 문법을 차용하고, 그 일부 기능만 제공한다.
AspectJ는 다음과 같이 소개하는데, 부가 기능의 역할을 잘 설명하고 있다.
- 자바 언어에 대한 완벽한 관점 지향 확장
- 횡단 관심사의 모듈화
- 오류검사 및 처리
- 동기화
- 캐싱
- 모니터링 및 로깅
AOP적용 방식
AOP란 간단하게 말해서 핵심 기능과 부가 기능의 코드를 분리하고 관리하는 것을 말한다.
그런데 결국 부가 기능을 핵심 기능에 더해 수행해야 하는데, 이 부가 기능 로직을 어떻게 실제 로직에 추가할 수 있을까?
여기에는 3가지 방법이 있다.
- 컴파일 시점
- 클래스 로딩 시점
- 런타임 시점
여태까지 알아온 방식은 3번 프록시 방식이었다. 이번에는 각 방법에 대해서 함께 알아보자.
- 컴파일 시점
.java를 컴파일러를 통해 .class파일을 생성할 때 부가 로직을 추가하는 방법이다.
AspectJ컴파일러가 컴파일하는 과정에 실제 로직에 부가 로직을 붙이는 방식이다.
- 클래스 로딩 시점
.class파일을 JVM 내부의 클래스 로더에 보관하는 과정에서 .class파일을 조작해 부가 기능 로직을 추가하는 방법이다.
이 시점에 애스펙트를 적용하는 것을 로드타임 위빙이라고 한다.
- 단점 : 자바를 실행할 때 특별한 옵션 'java -javaagent'을 통해 클래스 로더 조작기를 지정해야 하는데, 번거롭고 운영이 어려움
- 런타임 시점(프록시)
지금까지 했던 방식이다. 자바가 실행이된 후, 즉 main메서드가 실행된 후에 적용되는 방식이다.
따라서 자바 언어가 제공하는 범위 내에서 부가 기능을 적용할 수 있다. 앞서 했듯이 스프링 컨테이너, 프록시, DI, 빈 포스트 프로세서와 같은 여러 개념이 필요하다.
따라서 이 방식은 AOP기능에 제약은 있지만, 특별한 컴파일러나 클래스 로더 조작기 없이 스프링만으로 AOP를 적용할 수 있다.
각 방식의 차이
- 컴파일 시점 : 실제 대상 코드에 부가 기능 호출 코드가 포함됨, AspectJ를 직접 이용해야함
- 클래스 로딩 시점 : 실제 대상 코드에 부가 기능 호출 코드가 포함됨, AspectJ를 직접 이용해야함
- 런타임 시점 : 실제 대상 코드는 그대로 유지됨, 대신에 프록시를 통해 부가 기능이 적용됨
AOP 적용 위치(조인포인트)
AOP는 바이트코드를 실제로 조작하기 떄문에 생성자, 필드 값, static등 모든 지점에 기능을 적용할 수 있다.
하지만 프록시 방식의 경우 AOP는 메서드 실행 시점에만 적용할 수 있다.
- 프록시의 경우 오버라이딩의 개념으로 동작하기 때문에 생성자나 static메서드, 필드 값 접근에는 적용할 수 없다.
- 따라서 프록시의 졍우 조인 포인트는 메서드 실행으로 제한된다.
- 타겟 또한 스프링 컨테이너가 관리할 수 있는 스프링 빈에만 AOP를 적용할 수 있다.
AOP 용어
- 조인포인트
- 어드바이스가 적용될 수 있는 위치
- 메서드 실행, 생성자 호출, 필드 값 접근 등
- 추상적인 개념으로 AOP를 적용할 수 있는 모든 지점을 뜻함
- 스프링 AOP는 프록시 방식을 사용하므로 메서드 실행 시점으로 제한됨
- 포인트컷(Pointcut)
- 조인포인트 중 어드바이스가 적용될 위치를 선별하는 기능
- 주로 AspectJ 표현식으로 지정
- 타겟(Target)
- 어드바이스
- 부가 기능 로직
- Around, Before, After 등 다양한 종류의 어드바이스가 있음
- 에스펙트(Aspect)
- 어드바이스 + 포인트컷을 모듈화 한것
- @Aspect
- 여러 어드바이스, 포인트켓이 함께 존재
- 어드바이저(Advisor)
- 하나의 어드바이스 + 하나의 포인트 컷
- 스프링 AOP에서만 사용되는 용어
- 위빙(Weaving)
- 포인트컷으로 결정한 타겟의 조인 포인트에 어드바이스를 적용하는 것
- AOP 프록시
- AOP기능 구현을 위해 만든 프록시 객체
- JDK동적 프록시, CGLIB 프록시 등
출처 : 김영한 - 스프링 핵심 원리 고급편