Aspect
공통적인 부가 기능인 횡단 관심사를 위해 만들어진 것이 바로 Aspect
이다.
Aspect
는 관점이라는 뜻인데, 애플리케이션을 바라보는 관점을 각각의 기능에서 횡단 관심사 관점으로 본다는 의미이다.
이렇게 횡단 관심사를 처리하는 Aspect
를 사용한 프로그래밍 방식이 AOP(Aspect Oriented Programming)
!!
이는 객체 지향을 대체하는 것이 아닌 OOP만으로 처리하기 어려운 횡단 관심사를 보조하기 위한 목적을 가지고 있다.
Spring
이 제공하는Advisor
,Advice
,Pointcut
또한 하나의Aspect
라고 볼 수 있다.
AOP
AOP
의 가장 핵심 아이디어는 횡단 관심사를 분리하여 한 곳에서 관리하도록 하는 것이다.
AOP 적용 방식
AOP
에서 횡단 관심사를 처리하는 방식은 크게 3가지가 존재한다.
- 컴파일 시점
- 클래스 로딩 시점
- 런타임 시점(Proxy)
1. 컴파일 시점
컴파일러는 .java
파일을 컴파일해 .class
를 만든다.
.class
를 만드는 시점에 횡단 관심사를 추가해 AOP
를 적용할 수 있다.
하지만 이는 AspectJ
가 제공하는 컴파일러를 사용해야하는데, AspectJ
컴파일러가 해당 클래스가 Pointcut
적용 대상인지를 확인하고 횡단 관심사를 추가한다.(바이트 코드 조작)
이렇게 원본에 횡단 관심사를 추가하는 것을 위빙이라한다.
이 방식은
AspectJ
의 컴파일러를 사용해야하고 복잡하다는 단점이 존재한다.
2. 클래스 로딩 시점
자바의 동작과정에 대해 알고 있는 사람이라면 클래스 로딩의 뜻을 알고 있을 것이다.
컴파일러를 통해 생성된 .class
파일은 JVM
의 클래스 로더에 보관되고 클래스 로딩을 통해 JVM
위에서 동작한다.
클래스 로딩 시점은 JVM
에 저장하기 전에 횡단 관심사를 추가해 바이트 코드를 조작하는 방식의 AOP
를 의미한다.
이 방식은 자바를 실행할 때
java -javaagent
를 통해 조작기를 지정해야하므로 번거롭고 운영이 어렵다는 단점이 존재한다.
3. 런타임 시점
런타임 시점은 자바의 메인 메서드가 실행된 다음을 의미한다.
따라서, Spring Container
, Bean Post Processor
등의 도움을 받아 횡단 관심사를 적용해야하는데 최종적으로 Proxy
를 통해 Spring Bean
에 횡단 관심사를 적용하는 방식의 AOP
이다.
이 방식은
Proxy
를 사용하기 때문에 바이트 코드를 조작하는 다른 방식에 비해 제약이 있다.
AOP 적용 위치
AOP
적용 가능 지점(JoinPoint
): 생성자, 필드 값 접근,static
메서드 접근, 메서드 실행
컴파일 시점과 클래스 로딩 시점의 AOP
는 바이트코드를 조작하기 때문에 모든 지점에 횡단 관심사를 적용할 수 있다.
하지만, 런타임 시점의 Proxy
방식(Spring AOP
)는 메서드 실행 시점에만 AOP
를 적용할 수 있다.
Proxy
는 메서드 오버라이딩 방식으로 동작하므로, 생성자나static
메서드, 필드 값 접근에 적용될 수 없다.- 즉,
Spring AOP
는Spring Container
가 관리하는Spring Bean
에만 적용 가능하다.
Spring AOP
는 제약이 많지만 대부분의 복잡한 문제를 해결하기에 충분하고 별도의 추가 설정없이Spring
만으로 편리하게AOP
를 사용할 수 있다!!
AOP 용어
JoinPoint
AOP
를 적용할 수 있는 모든 지점Spring AOP
의JoinPoint
는 메서드 실행 지점
Pointcut
JoinPoint
중에서Advice
가 적용될 위치AspectJ Expression
을 사용Spring AOP
는 메서드 실행 지점만Pointcut
으로 선별 가능
target
Advice
가 적용되는 객체,Pointcut
으로 결정됨
Advice
- 부가 기능(횡단 관심사)
Around
,Before
,After
와 같은 다양한 종류의Advice
가 있음
Aspect
Advice
+Pointcut
을 모듈화한 것
Advisor
- 하나의
Advice
와 하나의Pointcut
으로 구성
- 하나의
AOP Proxy
JDK Dynamic Proxy
,CGLIB Proxy
Spring AOP 구현
1. @Around
사용
@Around
에AspectJ Expression
을 사용해 적용할 범위인pointcut
을 지정해준다.- 여기서
doLog
메서드가Advice
가 된다. Advice
를 적용하고joinPoint.proceed()
를 통해Target
을 호출한다.
2. @Pointcut
사용
@Pointcut
을 사용해pointcut
을 별도의 메서드로 분리하고@Around
에서 호출하는 방식으로AOP
를 적용한다.- 이 때 호출되는 메서드와 파라미터를 합쳐
pointcut signature
라고 부른다. - 메서드의 반환 타입은 반드시
void
여야하고, 내용은 비워준다. - 만약 다른
Apsect
에서 참고하려면public
접근 제어자를 사용하자. - 분리하면 하나의 포인트컷 표현식을 여러 곳에서 함께 사용할 수 있다는 장점이 존재한다.
3. @Pointcut
조합
@Around
에는&&
,||
,!
을 사용해pointcut
을 조합할 수 있다.
4. @Pointcut
모듈화
- 별도의 클래스에
@Pointcut
을 모아 모듈화를 진행한다. - 외부에서 참조할 것이기 때문에 접근 제어자를
public
으로 변경했다.
- 참조할 포인트컷 모듈의
패키지명.클래스명.메서드명
을@Around
에 작성해 외부에 있는@Pointcut
을 가져와 적용할 수 있다.
5. Advice 순서 지정
AOP
를 적용할 때 Advice
들의 순서를 지정해야할 때가 있을 것이다.
Spring
에서 제공하는 @Order
애노테이션을 사용해 순서를 지정할 수 있지만 이는 클래스 단위에 적용되기 때문에 하나의 @Aspect
안에 여러 Advice
가 존재한다면 사용할 수 없다.
이럴 때는 불편하지만 Advice
를 쪼개야한다.
- 각각의 클래스로 분리하거나 하나의 껍데기 클래스를 만들고 내부 클래스로 각각
@Aspect
을 적용하고@Order
를 사용해 순서를 지정해주면된다. @Order
의 숫자가 낮은 것이 우선 순위가 높다.- 이 때 각각의
@Aspect
가 적용된 클래스를Spring Bean
으로 등록해주어야한다.
Advice 종류
@Around
: 메서드 호출 전후에 수행되고 가장 강력한Advice
로써JoinPoint
실행 여부 선택, 반환 값 변환, 예외 반환 등이 가능@Before
:JoinPoint
실행 이전에 실행@After Returning
:JoinPoint
가 정상 완료후 실행@After Throwing
: 메서드가 예외를 던지는 경우 실행@After
:JoinPoint
의 동작에 관계없이 무조건 실행(finally)
@Before
, @After Returning
, @After Throwing
, @After
은 @Around
의 기능을 시점별로 나누어놓은 것이다.
- 이전에 사용했던
@Around
를 각 4개의 시점으로 나눠보면 위와 같이 나눌 수 있다.
@Before
joinPoint.proceed()
이전의 시점을 사용한다.- 참고로
@Before
을 사용한다면jointPoint.proceed()
를 직접 호출해주지 않아도 된다.(자동으로 호출해줌) - 또한 파라미터로는
ProceedingJoinPoint
가 아닌JoinPoint
를 사용해야함을 주의하자. - 예외가 발생했다면 다음 코드가 호출되지 않는다.
@AfterReturning
joinPoint.proceed()
가 수행되고 메서드가 정상적으로 반환될 때- 여기서는 직접 리턴을 받는 것이 아니기 때문에 그 값을 변경할 수는 없다.(조작은 가능)
- 애노테이션의
returning
속성으로 이름을 지정해주고 이를 꺼내서 사용할 수 있다. returning
절에 지정된 타입의 값을 반환하는 메서드만 대상으로 실행(부모 타입을 지정하면 모든 자식 타입은 허용)
@AfterThrowing
- 메서드가 예외를 던질 때 실행되는 로직
@After
- 일반적으로 리소스를 해제하는데 사용
모든 Advice는
JoinPoint
를 첫번째 파라미터에 사용할 수 있음(생략해도 됨)
하지만,
@Around
는 다음Advice
나Target
을 호출해야하므로ProceedingJoinPoint
를 사용해야함
@Around
- 메서드 실행 전후 모두에 작업을 수행할 수 있다.
JoinPoint
실행 여부를 선택할 수 있다.- 전달 값, 반환 값, 예외를 변환할 수 있다.
실행 순서
동일한 @Aspect
안에서 동일한 JoinPoint
의 우선순위가 정해져있다.
실행 순서 : @Around
-> @Before
-> @After
-> @AfterRetruning
-> @AfterThrowing
- 리턴 순서는 반대이다.
@Around
는 가장 넓은 기능을 제공하지만 생각해야할 범위가 넓어져 실수할 가능성이 존재한다.
하지만 @Before
, @After
는 기능은 적지만 실수할 가능성이 낮고 코드가 단순해지고 의도가 명확하다.
좋은 설계는 제약이 있는 것이다.
제약이 실수를 미연에 방지하는 가이드 역할을 해주기 때문이다.
'Spring > Spring Core Advanced' 카테고리의 다른 글
@Aspect AOP (0) | 2022.01.25 |
---|---|
빈 후처리기 (3) | 2022.01.15 |
Spring의 프록시 기술 (0) | 2021.12.16 |
동적 프록시 기술 (0) | 2021.11.18 |
프록시 패턴과 데코레이터 패턴 (0) | 2021.11.08 |