지난 포스팅에 이어, 이번 포스팅에서는 6) ~ 9)
까지의 내용을 정리한다.
👉 목차는 다음과 같다.
1) 빈 후처리기 - 소개
2) 빈 후처리기 - 예제 코드1
3) 빈 후처리기 - 예제 코드2
4) 빈 후처리기 - 적용
5) 빈 후처리기 - 정리
6) 스프링이 제공하는 빈 후처리기1
7) 스프링이 제공하는 빈 후처리기2
8) 하나의 프록시, 여러 Advisor 적용
9) 정리
바로 하나씩 확인해보자.
학습하기 전에 먼저 다음을 추가해주어야 한다. ( build.gradle
)
implementation 'org.springframework.boot:spring-boot-starter-aop'
aspectjweaver
라는 aspectJ
관련 라이브러리를 등록하고, 스프링 부트가 AOP 관련 클래스를 자동으로 스프링 빈에 등록한다. 스프링 부트가 없던 시절에는 @EnableAspectJAutoProxy
를 직접 사용해야 했는데, 이 부분을 스프링 부트가 자동으로 처리해준다. aspectJ
는 뒤에서 설명한다. 스프링 부트가 활성화하는 빈은 AopAutoConfiguration
를 참고하자.
자동 프록시 생성기 - AutoProxyCreator
AnnotationAwareAspectJAutoProxyCreator
라는 빈 후처리기가 스프링 빈에 자동으로 등록된다.Advisor
들을 자동으로 찾아서 프록시가 필요한 곳에 자동으로 프록시를 적용해준다.Advisor
안에는 Pointcut
과 Advice
가 이미 모두 포함되어 있다. 따라서 Advisor
만 알고 있으면 그 안에 있는 Pointcut
으로 어떤 스프링 빈에 프록시를 적용해야 할지 알 수 있다. 그리고 Advice
로 부가 기능을 적용하면 된다.AnnotationAwareAspectJAutoProxyCreator
는 @AspectJ와 관련된 AOP 기능도 자동으로 찾아서 처리해준다.Advisor
는 물론이고, @Aspect
도 자동으로 인식해서 프록시를 만들고 AOP를 적용해준다. @Aspect
에 대한 자세한 내용은 뒤에 설명한다.자동 프록시 생성기의 작동 과정
@Bean
, 컴포넌트 스캔 모두 포함)Advisor
를 조회한다. (어드바이저는 빈으로 등록되어 있어야 한다.)Advisor
에 포함되어 있는 포인트컷을 사용해서 해당 객체가 프록시를 적용할 대상인지 아닌지 판단한다. 이때 객체의 클래스 정보는 물론이고, 해당 객체의 모든 메서드를 포인트컷에 하나하나 모두 매칭해본다. 그래서 조건이 하나라도 만족하면 프록시 적용 대상이 된다. 예를 들어서 10개의 메서드 중에 하나만 포인트컷 조건에 만족해도 프록시 적용 대상이 된다.target
)을 알고 있다.
👉 코드를 통해 바로 적용해보자.
AutoProxyConfig
코드를 보면 advisor1
이라는 어드바이저 하나만 등록했다.AnnotationAwareAspectJAutoProxyCreator
) 빈 후처리기를 자동으로 등록해준다.http://localhost:8080/v1/request?itemId=hello
)http://localhost:8080/v2/request?itemId=hello
)http://localhost:8080/v3/request?itemId=hello
)
✔️ (중요) 포인트컷은 2가지에 사용된다.
orderControllerV1
은 request()
, noLog()
가 있다. 여기에서 request()
가 조건에 만족하므로 프록시를 생성한다.orderControllerV1
은 이미 프록시가 걸려있다.orderControllerV1
의 request()
는 현재 포인트컷 조건에 만족하므로 프록시는 어드바이스를 먼저 호출하고, target
을 호출한다.orderControllerV1
의 noLog()
는 현재 포인트컷 조건에 만족하지 않으므로 어드바이스를 호출하지 않고 바로 target
만 호출한다.
✔️ 참고
애플리케이션 로딩 로그
"request*", "order*", "save*"
만 포함되어 있으면 매칭 된다고 판단하기 때문이다.request
라는 단어만 들어가 있으면 프록시가 만들어지고 되고, 어드바이스도 적용되는 것이다. 👉 결론적으로 패키지에 메서드 이름까지 함께 지정할 수 있는 매우 정밀한 포인트컷이 필요하다.
AspectJExpressionPointcut
AspectJ라는 AOP에 특화된 포인트컷 표현식을 적용할 수 있다. AspectJ 포인트컷 표현식과 AOP는 조금 뒤에 자세히 설명하겠다.
지금은 특별한 표현식으로 복잡한 포인트컷을 만들 수 있구나 라고 대략 이해하면 된다.
코드로 적용해보자.
advisor1
에 있는 @Bean
은 주석처리해주어야 한다. 그렇지 않으면 어드바이저가 중복 등록된다.AspectJExpressionPointcut
: AspectJ 포인트컷 표현식을 적용할 수 있다.execution(* hello.proxy.app..*(..))
: AspectJ가 제공하는 포인트컷 표현식이다. 이후 자세히 설명하겠다. 지금은 간단히 알아보자.*
: 모든 반환 타입hello.proxy.app..
: 해당 패키지와 그 하위 패키지*(..)
: *
모든 메서드 이름, (..)
파라미터는 상관 없음hello.proxy.app
패키지와 그 하위 패키지의 모든 메서드는 포인트컷의 매칭 대상이 된다.http://localhost:8080/v1/request?itemId=hello
)http://localhost:8080/v1/no-log
)advisor2
에서는 단순히 package
를 기준으로 포인트컷 매칭을 했기 때문이다.advisor1
, advisor2
에 있는 @Bean
은 꼭 주석처리해주어야 한다. 그렇지 않으면 어드바이저가 중복 등록된다.execution(* hello.proxy.app..*(..)) && !execution(* hello.proxy.app..noLog(..))
&&
: 두 조건을 모두 만족해야 함!
: 반대hello.proxy.app
패키지와 하위 패키지의 모든 메서드는 포인트컷에 매칭하되, noLog()
메서드는 제외하라는 뜻이다.http://localhost:8080/v1/no-log
)
✔️ 참고
예를 들어서 어떤 스프링 빈이 advisor1
, advisor2
가 제공하는 포인트컷의 조건을 모두 만족하면 프록시 자동 생성기는 프록시를 몇 개 생성할까?
프록시 자동 생성기는 프록시를 하나만 생성한다. 왜냐하면 프록시 팩토리가 생성하는 프록시는 내부에 여러 advisor
들을 포함할 수 있기 때문이다. 따라서 프록시를 여러 개 생성해서 비용을 낭비할 이유가 없다.
프록시 자동 생성기 상황별 정리
advisor1
의 포인트컷만 만족advisor1
만 포함advisor1
, advisor2
의 포인트컷을 모두 만족advisor1
, advisor2
모두 포함advisor1
, advisor2
의 포인트컷을 모두 만족하지 않음자동 프록시 생성기인 AnnotationAwareAspectJAutoProxyCreator
덕분에 개발자는 매우 편리하게 프록시를 적용할 수 있다. 이제 Advisor
만 스프링 빈으로 등록하면 된다. ( Advisor = Pointcut + Advice
)
다음 섹션에서는 @Aspect
애노테이션을 사용해서 더 편리하게 포인트컷과 어드바이스를 만들고 프록시를 적용해보자.
강의를 듣고 정리한 글입니다. 코드와 그림 등의 출처는 김영한 강사님께 있습니다.