티스토리 뷰
[Spring]AOP - AspectJ, Pointcut Expression, Join Point
Vagabund.Gni 2022. 8. 17. 13:57Spring AOP
[Spring]AOP(Aspect Oriented Programming) - 용어 정리
AspectJ
AspectJ는 미국의 팰로앨토 연구소(영어: Palo Alto Research Center, PARC)에서 개발한
자바 프로그래밍 언어용 AOP 확장 기능(라이브러리)이다.
조금 더 구체적으로 AspectJ는 애너테이션이 있는 일반 Java 클래스로 Aspect를 선언하는 스타일이라고 볼 수 있다.
사실상 Java AOP 소프트웨어의 표준이라고 해도 될 정도로 널리 사용되고 있는 기능이며,
스프링 AOP에도 이 AspectJ를 이용한 AOP 구현을 위한 기능이 포함되어 있다.
여기서 스프링 AOP 실행환경은 AspectJ 컴파일러나 위버(Weaver)에 대한 의존성 없이 @AspectJ 애너테이션을 지원한다.
즉, AOP 런타임은 여전히 순수한 스프링 AOP이다.
이전 글에서 확인했던 스프링 AOP와는 또 다른 형태로 AOP를 구현할 수 있기 때문에, 알아두면 편하다.
천천히 알아보도록 하자.
- AspectJ 설정하기
스프링 설정에서 @AspectJ Aspect를 사용하기 위해서는 @AspectJ Aspect에 기반한 스프링 AOP 설정과
이러한 Aspect에 의해 Advice되는 프록시에 대한 자동 스프링 지원(빈 등록)을 활성화해야 한다.
조금 더 추가적으로 설명하자면 프록시를 빈으로 등록해주어야 하는데 ComponentScan시 stereo type 중에
@AspectJ가 없기 때문에 ComponentScan에 걸리지 않게 된다. 이를 위해 따로 애너테이션을 등록해준다고 보면 된다.
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}
@Configuration으로 @AspectJ 지원을 활성화하기 위해 @EnableAspectJAutoProxy 애너테이션을 추가했다.
- Aspect 선언
@AspectJ 지원이 활성화되면 @AspectJ Aspect(@Aspect 애너테이션이 존재)가 있는 클래스가 자동으로 감지되고
스프링 AOP를 구성하는 데 사용된다.
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class NotVeryUsefulAspect {
}
- 포인트컷(Pointcut) 정의
포인트컷은 Join Point를 결정해 Advice가 실행되는 시기를 지정한다.
스프링 AOP는 스프링 빈에 대한 메서드 실행 Join Point만을 지원하기 때문에,
스프링에서 Pointcut은 빈의 메서드 실행 지점을 지정하는 것으로 생각할 수도 있다.
Pointcut 선언은 @Pointcut 애너테이션을 사용하며, 이름과 매개변수를 포함하는 서명과
메서드 실행 시점을 정확히 결정하는 Pointcut 표현식 두 부분으로 구성된다.
@Aspect
public class PerfAspect {
@Pointcut("execution(* proxyexam.*.EventService.*(..))") // 포인트컷 표현식
public void targetMethod() { // 포인트컷 서명
// Pointcut 애너테이션 값을 참조하기 위한 dummy method
}
...
}
위 예제는 proxyexam 패키지 하위의 EventService 명으로 끝나는 클래스의
모든 메서드 실행과 일치할 'targetMethod' 라는 이름의 Pointcut을 정의한다.
- Advice 선언
Advice는 Pointcut 표현식과 연관되며 Pointcut과 일치하는 메서드 실행 전/후에 실행된다.
Pointcut이 Advice의 적용 위치라면 Advice는 그 내용이라고 볼 수도 있다.
Advice는 실행되는 시점에 따라 Before, After, Around 등으로 구분되며,
더 자세한 사항은 이전 글에 정리해 두었다.
관련 글: https://gnidinger.tistory.com/459
Pointcut Expression
위에서 짧게 살펴봤던 포인트컷 표현식에 대해 살펴보자.
다시 정리하자면 포인트컷은 Join Point를 결정해 Advice가 실행되는 시기를 지정한다.
스프링 AOP는 스프링 빈에 대한 메서드 실행 Join Point만을 지원하기 때문에,
스프링에서 Pointcut은 빈의 메서드 실행 지점을 지정하는 것으로 생각할 수도 있다.
AspectJ는 포인트컷을 편하게 표현할 수 있는 아래와 같은 표현식을 제공한다.
@Pointcut("execution(* proxyexam.*.EventService.*(..))") // 포인트컷 표현식
public void targetMethod() {} // 포인트컷 서명
따라서 일반적으로 포인트컷 표현식이란 AspectJ pointcut expression을 짧게 부르는 말이다.
- 포인트컷 지시자
포인트컷 표현식은 위에서 살펴본 execution 같은 포인트컷 지시자(Pointcut Designator, PCD)로 시작하며,
그 종류는 아래와 같다.
종류 | 설명 |
execution | 메서드 실행 조인 포인트 매칭. 스프링 AOP에서 가장 많이 사용하며, 기능도 복잡하다. |
within | 특정 타입 내의 조인 포인트 매칭 |
args | 인자가 주어진 타입의 인스턴스인 조인 포인트 매칭 |
this | 스프링 빈 객체(스프링 AOP 프록시)를 대상으로 하는 조인 포인트 매칭 |
target | 타켓 객체(스프링 AOP 프록시가 가르키는 실제 대상)를 대상으로 하는 조인 포인트 매칭 |
@target | 실행 객체의 클래스에 주어진 타입의 애너테이션이 있는 조인 포인트 매칭 |
@within | 주어진 애너테이션이 있는 타입 내 조인 포인트 매칭 |
@annotation | 메서드가 주어진 애너테이션을 가지고 있는 조인 포인트 매칭 |
@args | 전달된 실제 인수의 런타임 타입이 주어진 타입의 애너테이션을 갖는 조인 포인트 매칭 |
bean | 스프링 전용 포인트컷 지시자이며 빈의 이름으로 포인트컷을 지정 |
이중 execution을 가장 많이 사용하고 나머지는 자주 사용하지 않는다.
- 포인트컷 표현식 결합
&&, ||, !를 통해 포인트컷을 결합할 수 있다. 예는 아래와 같다.
@Pointcut("execution(public * *(..))")
private void anyPublicOperation() {} // (1)
@Pointcut("within(com.xyz.myapp.trading..*)")
private void inTrading() {} // (2)
@Pointcut("anyPublicOperation() && inTrading()")
private void tradingOperation() {} // (3)
(1)은 메서드 실행 조인 포인트가 공용 메서드의 실행을 나타내는 경우 일치하고
(2)는 메서드 실행이 거래 모듈에 있는 경우에 일치하기 때문에
(3)은 메서드 실행이 거래 모듈의 공용 메서드를 나타내는 경우 일치하게 된다.
- 일반적인 포인트컷 표현식들
Pointcut | Join Point |
execution(public * *(..)) | public 메서드 실행 |
execution(* set*(..)) | 이름이 set으로 시작하는 모든 메서드명 실행 |
execution(* com.xyz.service.AccountService.*(..)) | AccountService 인터페이스의 모든 메서드 실행 |
execution(* com.xyz.service.*.*(..)) | service 패키지의 모든 메서드 실행 |
execution(* com.xyz.service..*.*(..)) | service 패키지와 하위 패키지의 모든 메서드 실행 |
within(com.xyz.service.*) | service 패키지 내의 모든 조인 포인트 (Spring AOP에서만 메서드 실행) |
within(com.xyz.service..*) | service 패키지 및 하위 패키지의 모든 조인 포인트 (Spring AOP에서만 메서드 실행) |
this(com.xyz.service.AccountService) | AccountService 인터페이스를 구현하는 프록시 개체의 모든 조인 포인트 (Spring AOP에서만 메서드 실행) |
target(com.xyz.service.AccountService) | AccountService 인터페이스를 구현하는 대상 객체의 모든 조인 포인트 (Spring AOP에서만 메서드 실행) |
args(java.io.Serializable) | 하나의 파라미터를 갖고 전달된 인자가 Serializable인 모든 조인 포인트 (Spring AOP에서만 메서드 실행) |
@target(org.springframework.transaction.annotation.Transactional) | 대상 객체가 @Transactional 애너테이션을 갖는 모든 조인 포인트 (Spring AOP에서만 메서드 실행) |
@within(org.springframework.transaction.annotation.Transactional) | 대상 객체의 선언 타입이 @Transactional 애너테이션을 갖는 모든 조인 포인트 (Spring AOP에서만 메서드 실행) |
@annotation(org.springframework.transaction.annotation.Transactional) | 실행 메서드가 @Transactional 애너테이션을 갖는 모든 조인 포인트 (Spring AOP에서만 메서드 실행) |
@args(com.xyz.security.Classified) | 단일 파라미터를 받고, 전달된 인자 타입이 @Classified 애너테이션을 갖는 모든 조인 포인트 (Spring AOP에서만 메서드 실행) |
bean(accountRepository) | “accountRepository” 빈의 모든 조인 포인트 (Spring AOP에서만 메서드 실행) |
!bean(accountRepository) | “accountRepository” 빈을 제외한 모든 빈의 모든 조인 포인트(Spring AOP에서만 메서드 실행) |
bean(*) | 모든 빈의 모든 조인 포인트 (Spring AOP에서만 메서드 실행) |
bean(account*) | 이름이 'account'로 시작되는 모든 빈의 모든 조인 포인트(Spring AOP에서만 메서드 실행) |
bean(*Repository) | 이름이 “Repository”로 끝나는 모든 빈의 모든 조인 포인트(Spring AOP에서만 메서드 실행) |
bean(accounting/*) | 이름이 “accounting/“로 시작하는 모든 빈의 모든 조인 포인트(Spring AOP에서만 메서드 실행) |
bean(*dataSource) || bean(*DataSource) | 이름이 “dataSource” 나 “DataSource” 으로 끝나는 모든 빈의 모든 조인트 (Spring AOP에서만 메서드 실행) |
Join Point
스프링 AOP Advice는 위에 살펴본 메서드 외에도 생성자, 필드 값 등 다양한 위치에 적용할 수 있다.
조인 포인트는 이 Advice가 적용 가능한 지점을 말하며,
AOP를 수행하는 메서드는 JoinPoint 인스턴스를 인자로 받아 조인 포인트의 정보를 얻게 된다.
조인 포인트의 특징은 아래와 같다.
- AspectJ를 사용하는 AOP는 바이트코드를 실제 조작하기 때문에 모든 지점에 AOP를 적용할 수 있다
- 프록시는 메서드 오버라이딩 개념으로 동작한다.
- 생성자나 static 메서드, 필드 값 접근에는 프록시 개념이 적용될 수 없다.
- 프록시를 사용하는 스프링 AOP의 조인 포인트는 메서드 실행 지점으로 제한된다.
- 프록시를 사용하는 스프링 AOP는 스프링 컨테이너가 관리할 수 있는 스프링 빈에만 AOP를 적용할 수 있다.
- JoinPoint 메서드는 기본적으로 Advice 메서드에 매개변수로 선언만 하면 된다.
계속해서 조인 포인트의 주요 기능에 대해 살펴보자.
- JoinPoint.getArgs() - JoinPoint에 전달된 인자를 배열로 반환
- JoinPoint.getThis() - AOP 프록시 객체를 반환
- JoinPoint.getTarget() - AOP가 적용된 타겟 객체를 반환(클라이언트가 호출한 비즈니스 객체를 반환)
- JoinPoint.getSignature() - AOP가 적용된 메서드에 대한 설명을 반환
- 클라이언트가 호출한 메서드의 시그니처(리턴타입, 이름, 매개변수) 정보가 저장된 시그니처 객체를 반환
- 시그니처? - 객체가 선언하는 모든 연산의 이름, (연산이) 매개변수로 받아들이는 객체들, 연산의 반환 값
- getSignature()가 제공하는 메서드
- String getName() : 클라이언트가 호출한 메서드의 이름을 반환
- String toLongString() : 클라리언트가 호출한 메서드의 리턴 타입, 이름, 매개변수를 패키지 경로까지 포함해서 반환
- String toShortString() : 클라이언트가 호출한 메서드 시그니처를 축약한 문자열로 반환
- JoinPoint.toString() - AOP 적용 방법에 대한 설명을 인쇄
마지막으로 ProceedingJoinPoint 인터페이스의 주요 기능이다.
- proceed() : 다음 Advice나 Target 호출
'Java+Spring > Spring' 카테고리의 다른 글
[Spring]Spring MVC - Controller 클래스 구조 생성 및 설계 (0) | 2022.08.22 |
---|---|
[Spring]Spring MVC (4) | 2022.08.20 |
[Spring]AOP - JDK Dynamic Proxy, CGLib (2) | 2022.08.18 |
[Spring]AOP - 프록시 패턴(Proxy Pattern) & 스프링 AOP (0) | 2022.08.17 |
[Spring]AOP(Aspect Oriented Programming) - 용어 정리 (4) | 2022.08.16 |
[Spring]Spring DI(Dependency Injection) (0) | 2022.08.12 |
- Total
- Today
- Yesterday
- 여행
- 세계일주
- 자바
- 동적계획법
- 중남미
- Backjoon
- 리스트
- a6000
- Python
- 면접 준비
- 파이썬
- 세모
- 세계여행
- 기술면접
- 야경
- 남미
- 스프링
- 백준
- 칼이사
- spring
- 알고리즘
- 유럽여행
- BOJ
- 맛집
- 유럽
- Algorithm
- RX100M5
- 스트림
- 지지
- java
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |