[Spring Boot] AOP 설정
AOP에 대한 설명은 해당 글을 참고
링크 : https://jangjjolkit.tistory.com/6
AOP 상세 설명 참고
링크 : https://jangjjolkit.tistory.com/10
AOP 설정
@Component 와 @Aspect 어노테이션을 적용한 클래스를 생성한다. 내부 메소드는 @Around 어노테이션을 사용하여 호출을 제어한다.
@Aspect
@Component
public class SomeAspect {
@Around("execution(* com.some..controller..*Controller.*(..))")
public Object some(ProceedingJoinPoint pjp) throws Throwable {
// ...
}
}
- @Component
- 스프링 컨테이너에 빈(Bean)으로 등록하기 위한 어노테이션
- @Bean은 개발자가 제어할 수 없는 외부 라이브러리를 빈(Bean)으로 등록 시 사용하고, @Component는 개발자가 직접 정의한 클래스를 빈(Bean)으로 등록할 때 사용
- @Aspect
- AOP 기능을 하는 클래스의 클래스 레벨에 지정하는 어노테이션
- @Around
- 어드바이스의 종류 중 한 가지로 어드바이스는 총 5개 타입이 있음
- 그중 Around는 메소드의 호출 자체를 제어할 수 있기 때문에 어드바이스 중 가장 강력한 기능이라고 볼 수 있음
AOP Advice(어드바이스)
본문을 읽기 전 AOP 용어를 참고하면 좋다.
링크 : https://jangjjolkit.tistory.com/11
Advice(어드바이스) 는 각 동작 시점(JoinPoint)에 삽입되어 횡단 관심에 해당하는 공통 기능의 코드를 의미하며, 독립된 클래스의 메소드로 작성된다.
간단하게 말해, 어떤 동작 시점에 실행될 공통 기능을 구현한 모듈이다.
스프링에는 5개의 동작 시점이 제공된다.
- @Before: 비즈니스 메소드 실행 전 동작
- @AfterReturning: 비즈니스 메소드가 성공적으로 리턴되면 동작
- 단, 메소드 내부 리턴값이 존재하는 경우)
- @AfterThrowing: 비즈니스 메소드 실행 중, 예외가 발생하면 동작
- 예를 들어, try ~ catch 중 catch 블록에 해당
- @After: 비즈니스 메소드가 실행된 후 무조건 실행
- @Around: 메소드 호출 자체를 가로채서 비즈니스 메소드 실행 전&후 모두에 처리할 로직을 삽입할 수 있음
PointCut
위 예시코드를 보면 @Around 안에 execution 이라고 하는 명시자를 볼 수 있다. 이는 실제로 Advice가 적용되는 JoinPoint인 PointCut을 명시한 것이다.
PointCut에는 execution, within, bean이 있다.
1. execution
접근 제어자, 리턴 타입, 타입 패턴, 메소드, 파라미터 타입, 예외 타입 등을 조합해서 정교한 포인트컷을 만들 수 있다.
예시 | 설명 |
execution(BoardDTO select*(..)) | 리턴 타입이 BoardDTO 클래스이고, 메소드의 이름이 select로 시작하며, 파라미터가 0개 이상인 모든 메소드가 호출될 때 (0개 이상은 패키지, 메소드, 파라미터 등 모든 것을 의미) |
execution(* com.board.controller.*()) | 해당 패키지 밑에 파라미터가 없는 모든 메소드가 호출될 때 |
execution(* com.board.controller.*(..)) | 해당 패키지 밑에 파라미터가 0개 이상인 모든 메소드가 호출될 때 |
execution(* com.board..select(*)) | com.board 패키지의 모든 하위 패키지에 존재하는 select로 시작하고, 파라미터가 한 개인 모든 메소드가 호출될 때 |
execution(* com.board..select(*, *)) | com.board 패키지의 모든 하위 패키지에 존재하는 select로 시작하고, 파라미터가 두 개인 모든 메소드가 호출될 때 |
execution(* com.board..controller.*Controller.*(..)) | com.board 패키지의 모든 하위 패키지 중 controller로 시작하는 패키지에서 xxxController와 같은 패턴의 이름을 가진 클래스에서 파라미터가 0개 이상인 메소드를 의미 |
execution(* com.board..service.*Impl.*(..)) | com.board 패키지의 모든 하위 패키지 중 service로 시작하는 패키지에서 xxxServceImpl과 같은 패턴의 이름을 가진 클래스에서 파라미터가 0개 이상인 메소드를 의미 |
execution(* com.board..mapper.*Mapper.*(..)) | com.board 패키지에서 모든 하위 패키지 중 mapper로 시작하는 패키지에서 xxxMapper와 같은 패턴의 이름을 가진 인터페이스에서 파라미터가 0개 이상인 메소드를 의미 |
2. within
명시된 객체 내부에 있는 모든 메소드를 포인트컷으로 한다.
예시 | 설명 |
within(com.board.service.SomeService) | com.board.service.SomeService 의 모든 메소드 |
within(com.board.service.*) | com.board.service 패키지의 모든 메소드 |
within(com.board.service..*) | com.board.service 패키지 및 하위 패키지의 모든 메소드 |
3. bean
명시된 빈의 모든 메소드를 포인트컷으로 한다.
예시 | 설명 |
bean(someBean) | 이름이 someBean인 빈의 모든 메소드 |
bean(some*) | 이름이 some 으로 시작하는 빈의 모든 메소드 |
* etc. @annotation, @within
특정 어노테이션이 설정된 모든 메소드를 포인트컷으로 한다.
예시 | 설명 |
@annotation(someAnnotation) | someAnnotation 이 명시된 모든 메소드 |
@within(org.springframework.web.bind.annotation.RestController) | 클래스 레벨에 특정 어노테이션이 명시된 모든 메소드 |
* 포인트컷 표현식은 and(&&) 또는 or(||)를 조합해서 사용할 수 있다.
ex) @Around(execution(BoardDTO select*(..)) && execution(* com.board.controller.*()))
ProceedingJoinPoint and ETC
ProceedingJoinPoint 인터페이스가 상속받는 클래스는 다음의 메소드를 포함한다.
메서드 | 설명 |
Object[] getArgs() | 전달되는 모든 파라미터들을 Object 타입의 배열로 가지고 온다. |
String getKind() | 해당 어드바이스(Advice)의 타입을 가지고 온다. |
Signature getSignature() | 실행되는 대상 객체의 메서드에 대한 정보를 가지고 온다. |
Object getTarget() | 타겟(Target) 객체를 가지고 온다. |
Object getThis() | 어드바이스(Advice)를 행하는 객체를 가지고 온다. |