-
빈 후처리기스프링/스프링 AOP 2023. 9. 17. 22:13
빈 후처리기란?
빈 후처리기는 빈을 조작하고 변경할 수 있는 기능이다.
빈 객체를 조작하거나 다른 객체로 바꿔 버릴정도로 강력한 기능이다.
일반적으로 스프링 컨테이너가 등록하는 빈들, 특히 컴포넌트 스캔의 대상이 되어서 의존관계 주입이 자동으로 이루어지는 빈들은 중간에 조작할 방법이 없는데, 빈 후처리기를 사용하면 개발자가 등록하는 모든 빈을 중간에 조작할 수 있다.
즉, 빈 객체를 프록시로 교체하는 것도 가능하다는 뜻이다.
스프링에서 지원하는 빈 후처리기 기능을 알아볼 것이다.
build.gradle에 추가
implementation 'org.springframework.boot:spring-boot-starter-aop'
위의 코드를 build.gradle에 추가하면 스프링 자동 빈 후처리가 스프링으로 등록된다.
- AnnotationAwareAspectJAutoProxyCreator
이러한 빈 후처리기는 스프링 빈으로 등록된 어드바이저들을 자동으로 찾아서 프록시가 필요한 곳에 자동으로 프록시를 적용해준다.
어드바이저 안에 포인트컷과 어드바이스가 포함되어 있기 때문에 어드바이저만 알고 있으면 그 안에 있는 포인트컷을 활용해서 어떤 스프링 빈에 프록시를 적용해야 할 지 자동으로 판단해서 적용해준다.
1. 스프링 빈을 생성
2. 생성된 객체를 빈 저장소에 등록하기 직전에 빈 후처리기에 전달
3. 모든 Advisor 빈 조회
4. 포인트컷을 하나하나 매칭해서 프록시 적용 대상 체크
5. 프록시 대상이면 프록시를 생성하고 반환해서 프록시를 스프링 빈으로 등록, 만약 적용 대상이 아니라면 원본 객체를 반환해서 원본 객체를 스프링으로 반환
6. 반환된 객체는 스프링 빈으로 등록
AutoProxyConfig.class
@Configuration @Import({AppV1Config.class, AppV2Config.class}) public class AutoProxyConfig { @Bean public Advisor advisor1(LogTrace logTrace) { NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut(); pointcut.setMappedNames("request*", "order*", "save*"); LogTraceAdvice advice = new LogTraceAdvice(logTrace); //advisor = pointcut + advice return new DefaultPointcutAdvisor(pointcut, advice); } }
스프링 자동 빈 후처리기는 어드바이저를 스프링 빈으로 등록하면 스프링이 자동으로 설정을 해주기 때문에 이후 설정을 해줄 필요가 없다.
프록시를 모든 곳에 생성하는 것은 비용 낭비이기 때문에 꼭 필요한 곳에 최소한의 프록시를 적용해야 한다.
그래서 자동 프록시 생성기는 모든 스프링 빈에 프록시를 적용하는 것이 아니라 포인트컷으로 한번 필터링해서 어드바이스가 사용될 가능성이 있는 곳에만 프록시를 생성한다.AspectJExpressionPointcut
위와 같은 방식은 효율적이지만 프록시 객체까지 AOP로 적용되기 때문에
사용자의 호출시점이 아니라 스프링 run 시점에서도 이런 로그가 찍힌다.
이러한 문제점을 해결하기 위해 포인트컷은 매우 정교하게 설정해야하며 실무에서는 거의 AspectJExpressionPointcut만 쓰인다.
@Bean public Advisor advisor(LogTrace logTrace) { // pointcut AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut(); pointcut.setExpression("execution(* hello.proxy.app..*(..)) && !execution(* hello.proxy.app..noLog(..))"); // advice LogTraceAdvice advice = new LogTraceAdvice(logTrace); // advisor = pointcut + advice return new DefaultPointcutAdvisor(pointcut, advice); }
AspectJExpressionPoincut을 사용하고 setExpression으로 경로를 지정해주면 app 리포지토리에 있는 controller, repository, service 계층에만 적용이 된다. &&를 통해 뒤에 있는 execution은 프록시를 사용해서 로그를 찍지 않는 메서드인 noLog를 제외했다.
이 문법은 너무 중요하기 때문에 다음 포스팅에서 이것만 중점적으로 다시 정리할 것이다.
하나의 프록시에 여러 어드바이저 적용
이전에서 말했듯이 프록시가 생성될 때마다 그만큼의 어드바이저를 생성하는 것이 아니라, 하나의 프록시에 여러 어드바이저를 적용하는 것이 가능하다.
프록시를 여러개 생성하는 것이 아니라 프록시 하나에 어드바이저가 여러개가 들어갈 수 있다는 것을 잘 기억해두면 된다.
'스프링 > 스프링 AOP' 카테고리의 다른 글
@Pointcut - 포인트컷 분리 (0) 2023.09.22 @Aspect 프록시 (0) 2023.09.20 어드바이저의 실제 적용 (0) 2023.09.17 여러 어드바이저 동시 적용 (0) 2023.09.17 포인트컷, 어드바이스, 어드바이저 (0) 2023.09.17