Home Spring AOP(3)
Post
Cancel

Spring AOP(3)

@EnableAspectJAutoProxy

기본적으로 ProxyFactory 클래스를 사용하여 AOP 프록시를 생성하고 관리할 수 있지만 이는 수동적이며 번거로운 작업입니다. 그렇기 때문에 Spring은 프록시 생성과 관리의 작업을 자동화하고 추상화한 org.springframework.context.annotation.EnableAspectJAutoProxy 어노테이션을 제공합니다. @EnableAspectJAutoProxy는 IoC 컨테이너가 org.aspectj.lang.annotation.Aspect가 적용된 클래스를 스캔하고, 필요한 프록시를 자동으로 생성하여 AOP를 적용할 수 있게끔 설정합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

  /**
   * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
   * to standard Java interface-based proxies. The default is {@code false}.
   */
  boolean proxyTargetClass() default false;
  
  /**
   * Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
   * for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
   * Off by default, i.e. no guarantees that {@code AopContext} access will work.
   * @since 4.3.1
   */
  boolean exposeProxy() default false;
}
  • proxyTargetClass: AOP Proxy 전략을 설정합니다.
  • 기본 값으로 false이며 CGLIB를 사용하며 true로 변경 시 JDK Dynamic을 사용합니다.
  • exposeProxy: 프록시 객체를 외부로 노출할지를 설정하는 필드입니다.

동작 방식

먼저 동작 방식을 살펴 보기 이전에 Pointcut으로 활용할 어노테이션을 생성합니다.

1
2
3
4
@Retention(value = RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SampleAop {
}

그 후 @Aspect 어노테이션으로 관리할 Advisor 클래스를 생성합니다. Advisor는 IoC 컨테이너에서 관리되어야 하기 때문에 Bean으로 등록합니다.

sample-aspect

또한 SampleAop 어노테이션을 대상 객체 메소드에 작성합니다.

1
2
3
4
5
6
7
8
@Service
public class SampleConcreteService {

  @SampleAop
  public String get() {
      return "Hello AOP";
  }
}

sample-concrete-service-test.png

위와 같이 설정을 완료 한 후 코드를 실행하여 어떤 식으로 프록시를 생성하며 사용하는지 확인해 보겠습니다.

스캔 및 등록

AnnotationAwareAspectJAutoProxyCreator

annotation-aware-aspectj-auto-proxy-creator.png
AnnotationAwareAspectJAutoProxyCreator는 모든 @Aspect 어노테이션을 처리하는 org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator의 구체 클래스이며 @Aspect 어노테이션이 선언되어 있는 클래스 스캔하고 해당 클래스를 기반으로 프록시를 생성합니다.
현재 애플리케이션 컨텍스트의 모든 @Aspect 뿐만아니라 Spring Advisor도 처리하며 생성된 프록시 객체를 IoC 컨테이너에 빈으로 등록합니다.

애플리케이션이 구동되면 AnnotationAwareAspectJAutoProxyCreator는 먼저 Spring Advisor 후보 클래스들을 스캔합니다. 만일 존재하지 않는다면 빈 리스트를 반환합니다.

find-advisor-beans.png

그 후 반환 받은 Advisors 이 외에 자동 프록시 객체들을 스캔하기 위해 BeanFactoryAspectJAdvisorsBuilder.buildAspectJAdvisors() 메소드를 실행시킵니다.

build-aspectj-advisors.png

메소드 내부를 확인해보면 IoC 컨테이너에서 관리 중인 빈들을 조회한 후 그 중 @Aspect 어노테이션이 선언되어 있는 빈들을 찾습니다.

is-aspect.png

찾은 @Aspect 어노테이션이 선언 되어 있는 빈을 찾았다면 해당 빈에서 Advisor를 찾기 위해 ReflectiveAspectJAdvisorFactory.getAdvisors() 메소드를 통해 계속해서 작업합니다.

ReflectiveAspectJAdvisorFactory

org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory는 Advice 메소드를 호출하기 위해 리플렉션 API를 사용하여 Advisor를 생성하는 팩토리 클래스입니다. 식별된 Aspect 클래스의 모든 메소드를 리플렉션 API를 사용하여 추출하고 해당 메소드 하나하나 Advisor인지 확인하고 등록합니다. 먼저 애플리케이션에서 관리하는 모든 Advisor 메소드들을 조회합니다.

get-advisors.png

먼저 해당 클래스가 Aspect가 맞는지부터 AspectJ가 지원하는 Aspect 인스턴스인지 검증합니다.

validate.png

그 후 조회한 Aspect 후보 클래스들의 후보 Advice 메소드가 적절한 Pointcut이 있는지 찾아서 등록합니다.

check-pointcut.png

이렇게 존재하는 모든 Advisor 객체를 찾아 등록한 다음 캐시에까지 등록함으로써 모든 프록시 생성을 끝마치며 buildAspectJAdvisors() 메소드는 종료합니다.

put-cache.png

빈 후처리

AbstractAutoProxyCreator

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreatorBeanPostProcessor를 구현한 클래스로 빈 후처리기로 동작합니다. Bean을 AOP 프록시로 래핑하고 Bean 자체를 호출하기 전에 적합한 인터셉터에 등록시킵니다.

wrap-if-necessary.png

매개변수로 들어온 Bean(대상 객체)이 Adivce에 적용된다면 getAdvicesAndAdvisorsForBean() 메소드를 통해 등록된 모든 Advisor들을 가져옵니다. 그 후 ProxyFactory 는 설정에 따라 전략을 선택하여 프록시를 생성하며 사용 가능한 Pointcut을 가진 Advisor만을 인터셉터로 등록합니다.

build-proxy-1.png

build-proxy-2.png

정리

Spring AOP는 어노테이션을 기반으로 프록시를 자동으로 생성하고, 관리해주는 기능을 제공해줍니다. @@EnableAspectJAutoProxy 어노테이션을 제공함으로써 자동 프록시 생성 관련 설정을 진행할 수 있습니다만 기본 설정은 true로 설정되어 있습니다.

어노테이션 기반으로 프록시를 자동으로 생성하기 위해서 ProxyFactory를 한 번더 추상화하여 제공하는 AnnotationAwareAspectJAutoProxyCreator를 통해서 생성합니다. @Aspect 어노테이션이 명시 되어 있는 Advisor들을 찾아 IoC 컨테이너에 빈으로 등록합니다.

그 후 AbstractAutoProxyCreator라는 빈 후처리기를 통해 등록된 Advisor들의 Pointcut에 해당하는 대상 객체에 대한 Advisor를 적용한 프록시를 생성하여 해당 프록시를 IoC 컨테이너에 등록합니다.

오탈자 및 오류 내용을 댓글 또는 메일로 알려주시면, 검토 후 조치하겠습니다.