ProxyFactory를 한번더 추상화한 Layer로 Asepect를 Annotation을 이용해 쉽게 AOP를 등록할 수 있다
@EnableAspectJAutoProxy같은경우 자동으로 추가되게 설정되어져있다@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
false = Interface기반 리플렉션 AOP
true = Class기반 CGLIB AOP
Import를 따라가보면
AspectJAutoProxyRegistrar.class
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
...
}
AopConfigUtils.class
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
registerAspectJAnnotationAutoProxyCreatorIfNecessary이부분을 통해
위사진과 같이 Asepect에 필요한 클래스들을 불러온다우리가 @Aspect 어노테이션을 통해 Advice를 등록할 수 있게 도와주는 클래스이다
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
...
@Override
protected List<Advisor> findCandidateAdvisors() {
List<Advisor> advisors = super.findCandidateAdvisors();
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
...
}
findCandidateAdvisors를 통해 모든 후보 Advice를 찾아온다
이때 buildAspectJAdvisors를 통해 Advice를 선발한다
BeanFactoryAspectJAdvisorsBuilder.java
public List<Advisor> buildAspectJAdvisors() {
...
List<Advisor> advisors = new ArrayList<>();
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
...
if (this.advisorFactory.isAspect(beanType)) {
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
...
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
...
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
...
advisors.addAll(classAdvisors);
...
}
}
...
}
return advisors;
}
현재 등록되어있는 모든 Asepect로부터 BeanName에 해당하는 Aspect를 뿌려주는 부분이다
여기서 getAdvisors부분만 추가로 살펴보자
먼저 해당 클래스의 상위클래스인 AbstractAspectJAdvisorFactory에 대해 간략히 짚고 넘어가자
AbstractAspectJAdvisorFactory.class
@Override
public void validate(Class<?> aspectClass) throws AopConfigException {
Class<?> superclass = aspectClass.getSuperclass();
if (superclass.getAnnotation(Aspect.class) != null &&
!Modifier.isAbstract(superclass.getModifiers())) {
...
}
...
}
@Nullable
private static <A extends Annotation> AspectJAnnotation<A> findAnnotation(Method method, Class<A> toLookFor) {
A result = AnnotationUtils.findAnnotation(method, toLookFor);
if (result != null) {
return new AspectJAnnotation<>(result);
}
else {
return null;
}
}
protected static class AspectJAnnotation<A extends Annotation> {
static {
annotationTypeMap.put(Pointcut.class, AspectJAnnotationType.AtPointcut);
annotationTypeMap.put(Around.class, AspectJAnnotationType.AtAround);
annotationTypeMap.put(Before.class, AspectJAnnotationType.AtBefore);
annotationTypeMap.put(After.class, AspectJAnnotationType.AtAfter);
annotationTypeMap.put(AfterReturning.class, AspectJAnnotationType.AtAfterReturning);
annotationTypeMap.put(AfterThrowing.class, AspectJAnnotationType.AtAfterThrowing);
}
}
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
...
validate(aspectClass);
...
}
Aspect Annotation이 존재하는지 확인하는 validate메서드와 현재 메서서드에 붙어있는 Annotation정보를 가져온다
본론으로 돌아와서
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass(); // 대상클래스
...
validate(aspectClass); // 검증
...
List<Advisor> advisors = new ArrayList<>();
for (Method method : getAdvisorMethods(aspectClass)) { // 메서드 리스트
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName); // Advisor 식별
if (advisor != null) {
advisors.add(advisor); // 등록
}
}
...
return advisors;
}
위와같이 대상클래스를 가져오고 식별한뒤 Aspect라면 메서드를 불러와서 하나하나 Advisor인지 구분하고 맞다면 이를 등록하는 과정을 거친다
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
getAdvisor를 통해 메서드에 대한 검증 및 Pointcut을 등록한다
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
Pointcut을 찾아올 때 상위 클래스에서 정의한 findAnnotation을 사용한다
이렇게 Adivsor객체를 생성하고 등록시킨다 또한 매번 생성시킬 순 없으니 캐시에 등록하는 모습도 볼 수 있었다
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
...
// 위에서 확인한 findCandidateAdvisors를 내부적으로 호출
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
...
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
...
return proxy;
}
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
...
return wrapIfNecessary(bean, beanName, cacheKey);
...
}
AbstractAutoProxyCreator또한 BestPostProcessor이므로 After작업중 wrapIfNecessary의 getAdvicesAndAdvisorsForBean를 통해 findCandidateAdvisors를 호출해 사용가능한 Advisors객체들을 가져온다
findCandidateAdvisors를통해 모든 Advisors가 불러와졌고최종반환은 실제 PointCut에 해당하는 Advisors만 specificInterceptors로 등록된다