Spring AOP源码解析(下)

导读:本篇文章讲解 Spring AOP源码解析(下),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

《Spring AOP源码分析(上)》介绍了在Spring AOP生成代理对象并作为Bean实例,以及@Before、@Around等注解的解析都是靠@EnableAspectJAutoProxy注解来完成的,这篇文章重点介绍该注解是如何实现上述功能的

一、注册AutoProxyCreator

@EnableAspectJAutoProxy注解如下,该注解通过@Import来加载AspectJAutoProxyRegistrar配置类,该配置类实现了ImportBeanDefinitionRegistrar接口,可以通过接口的registerBeanDefinitions()方法注册BeanDefinition

同时,@EnableAspectJAutoProxy提供了两个属性,proxyTargetClass()为true时会使用CGLIB进行动态代理,exposeProxy()为true时会把生成的代理对象添加到当前线程的ThreadLocal中

@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

   boolean proxyTargetClass() default false;

   
   boolean exposeProxy() default false;

}

注册AnnotationAwareAspectJAutoProxyCreator,如果@EnableAspectJAutoProxy的属性为true,就把这两个属性值添加到AnnotationAwareAspectJAutoProxyCreator的BeanDefinition的propertyValues中

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

   /**
    * Register, escalate, and configure the AspectJ auto proxy creator based on the value
    * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
    * {@code @Configuration} class.
    */
   @Override
   public void registerBeanDefinitions(
         AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

      // 注册一个AnnotationAwareAspectJAutoProxyCreator类型的Bean,beanName为AUTO_PROXY_CREATOR_BEAN_NAME
      AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

      // 修改AnnotationAwareAspectJAutoProxyCreator中对应的属性
      AnnotationAttributes enableAspectJAutoProxy =
            AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
      if (enableAspectJAutoProxy != null) {
         if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
            AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
         }
         if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
            AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
         }
      }
   }

}

添加proxyTargetClass属性值

public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
   if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
      BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
      definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
   }
}

二、生成代理对象

AnnotationAwareAspectJAutoProxyCreator继承自AbstractAutoProxyCreator,是一个BeanPostProcessor,在Bean实例创建过程的初始化后中,会调用postProcessAfterInitialization()方法判断是否需要进行AOP,如果需要AOP则创建一个代理对象返回

该方法在解决循环依赖的时候也有用到,如果当前Bean已经进行过AOP,则不会再次执行,否则将会调用wrapIfNecessary()方法来判断是否需要进行AOP以及生成AOP代理对象

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
   if (bean != null) {
      Object cacheKey = getCacheKey(bean.getClass(), beanName);
      if (this.earlyProxyReferences.remove(cacheKey) != bean) {
         return wrapIfNecessary(bean, beanName, cacheKey);
      }
   }
   return bean;
}

2.1 判断是否需要进行AOP

如果缓存advisedBeans已经记录了当前beanName不需要进行AOP,就直接返回

isInfrastructureClass()判断当前Bean是否为Advice、Pointcut、Advisor或AopInfrastructureBean,这些接口的实现类不能进行AOP,并且缓存一下这些Bean不能进行AOP

通过getAdvicesAndAdvisorsForBean()查找相匹配的Advisor,如果存在相匹配的,则需要进行AOP

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
        return bean;
    }
    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
        return bean;
    }

    // 当前正在创建的Bean不用进行AOP,比如切面Bean
    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
    }

    // Create proxy if we have advice.
    // 判断当前bean是否存在匹配的advice,如果存在则要生成一个代理对象
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    ……
}

isInfrastructureClass()源码

protected boolean isInfrastructureClass(Class<?> beanClass) {
    boolean retVal = Advice.class.isAssignableFrom(beanClass) ||
        Pointcut.class.isAssignableFrom(beanClass) ||
            Advisor.class.isAssignableFrom(beanClass) ||
                AopInfrastructureBean.class.isAssignableFrom(beanClass);
    if (retVal && logger.isTraceEnabled()) {
        logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]");
    }
    return retVal;
}

2.2 查找Advisor

getAdvicesAndAdvisorsForBean()方法中调用findEligibleAdvisors()查找Advisor

protected Object[] getAdvicesAndAdvisorsForBean(
    Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {

    // 寻找匹配的Advisor
    List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
    if (advisors.isEmpty()) {
        return DO_NOT_PROXY;
    }
    return advisors.toArray();
}

调用findCandidateAdvisors()方法找到所有Advisor,然后进行筛选,最近对这些Advisor按照order值进行排序

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    // 找到所有的Advisor
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // 进行筛选
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);

    extendAdvisors(eligibleAdvisors);

    // 对Advisor进行排序,按Ordered接口、@Order注解进行排序
    if (!eligibleAdvisors.isEmpty()) {
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}

在Spring AOP中,查找Advisor分为两类,一种是实现了Advisor接口,另一种是在切面类中通过@Before、@Around等注解定义的Advisor

protected List<Advisor> findCandidateAdvisors() {
   // Add all the Spring advisors found according to superclass rules.
   // 先找到所有Advisor类型的Bean对象
   List<Advisor> advisors = super.findCandidateAdvisors();

   // Build Advisors for all AspectJ aspects in the bean factory.
   // 再从所有切面中解析得到Advisor对象
   if (this.aspectJAdvisorsBuilder != null) {
      advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
   }
   return advisors;
}

2.2.1 查找实现Advisor接口的Advisor

通过beanNamesForTypeIncludingAncestors()获取所有实现了Advisor接口的BeanDefinition的beanName,然后通过getBean()方法创建Bean实例,然后添加到advisors中返回

public List<Advisor> findAdvisorBeans() {
    // Determine list of advisor bean names, if not cached already.
    String[] advisorNames = this.cachedAdvisorBeanNames;
    if (advisorNames == null) {
        // Do not initialize FactoryBeans here: We need to leave all regular beans
        // uninitialized to let the auto-proxy creator apply to them!
        advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
            this.beanFactory, Advisor.class, true, false);
        this.cachedAdvisorBeanNames = advisorNames;
    }
    if (advisorNames.length == 0) {
        return new ArrayList<>();
    }

    for (String name : advisorNames) {
        advisors.add(this.beanFactory.getBean(name, Advisor.class));
    }
    return advisors;
}

2.2.2 查找切面类中的Advisor

把所有的beanName都拿出来,然后根据Bean类型依次判断是否有Aspect注解,如果有该注解,则调用getAdvisors()获取切面中的Advisor

public List<Advisor> buildAspectJAdvisors() {
    // aspectBeanNames是用来缓存BeanFactory中所存在的切面beanName的,第一次为null,后面就不为null了,不为null表示之前就已经找到过BeanFactory中的切面了
    List<String> aspectNames = this.aspectBeanNames;
    if (aspectNames == null) {
        synchronized (this) {
            aspectNames = this.aspectBeanNames;
            if (aspectNames == null) {
                List<Advisor> advisors = new ArrayList<>();

                // 把所有beanNames拿出来遍历,判断某个bean的类型是否是Aspect
                String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                    this.beanFactory, Object.class, true, false);
                for (String beanName : beanNames) {
                    
                    // We must be careful not to instantiate beans eagerly as in this case they
                    // would be cached by the Spring container but would not have been weaved.
                    Class<?> beanType = this.beanFactory.getType(beanName, false);
                   
                    if (this.advisorFactory.isAspect(beanType)) {
                        aspectNames.add(beanName);
                        AspectMetadata amd = new AspectMetadata(beanType, beanName);

                        // 如果@Aspect不是perthis、pertarget,那么一个切面只会生成一个对象(单例)
                        // 并且会将该切面中所对应的Advisor对象进行缓存
                        if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {

                            MetadataAwareAspectInstanceFactory factory =
                                new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                            // 利用BeanFactoryAspectInstanceFactory来解析Aspect类
                            List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                            if (this.beanFactory.isSingleton(beanName)) {
                                // 缓存切面所对应的所有Advisor对象
                                this.advisorsCache.put(beanName, classAdvisors);
                            }
                            else {
                                this.aspectFactoryCache.put(beanName, factory);
                            }
                            advisors.addAll(classAdvisors);
                        }
                    }
                    ……
                }
            }
        }
    }
}

通过getAdvisorMethods获取切面类的方法,然后调用getAdvisor()生成Advisor对象

public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
   Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
   String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
   validate(aspectClass);

   // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
   // so that it will only instantiate once.
   MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
         new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

   List<Advisor> advisors = new ArrayList<>();
   // 获取切面类中没有加@Pointcut的方法,进行遍历生成Advisor
   for (Method method : getAdvisorMethods(aspectClass)) {
     
      Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
      if (advisor != null) {
         advisors.add(advisor);
      }
   }
	……

   return advisors;
}

getAdvisorMethods()方法获取切面类中所有没有加@Pointcut注解的方法,然后对方法进行排序

private List<Method> getAdvisorMethods(Class<?> aspectClass) {
    List<Method> methods = new ArrayList<>();
    // 拿到切面类中所有没有加@Pointcut的方法
    ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter);
    // 对方法进行排序,按注解和方法名字进行排序
    if (methods.size() > 1) {
        methods.sort(adviceMethodComparator);
    }
    return methods;
}

private static final MethodFilter adviceMethodFilter = ReflectionUtils.USER_DECLARED_METHODS
    .and(method -> (AnnotationUtils.getAnnotation(method, Pointcut.class) == null));

排序规则如下:

按照Around、Before、After、AfterReturning、AfterThrowing注解优先级进行排序,具有相同注解的方法按照方法名进行排序

private static final Comparator<Method> adviceMethodComparator;

static {
   Comparator<Method> adviceKindComparator = new ConvertingComparator<>(
         new InstanceComparator<>(
               Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
         (Converter<Method, Annotation>) method -> {
            AspectJAnnotation<?> ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
            return (ann != null ? ann.getAnnotation() : null);
         });
   Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
   adviceMethodComparator = adviceKindComparator.thenComparing(methodNameComparator);
}

getAdvisor()方法中,首先获取Pointcut对象,然后实例InstantiationModelAwarePointcutAdvisorImpl,生成Advisor

public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
      int declarationOrderInAspect, String aspectName) {

   validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());

   // 拿到当前方法所对应的Pointcut对象,但是注意:如果当前方法上是这么写的@After("pointcut()"),那么此时得到的Pointcut并没有去解析pointcut()得到对应的表达式
   AspectJExpressionPointcut expressionPointcut = getPointcut(
         candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
   if (expressionPointcut == null) {
      return null;
   }

   // expressionPointcut是pointcut
   // candidateAdviceMethod承载了advice
   return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
         this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

在InstantiationModelAwarePointcutAdvisorImpl方法中,会通过instantiateAdvice()得到一个Advisor,

public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
                                                  Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
                                                  MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
	……

    // A singleton aspect.
    this.pointcut = this.declaredPointcut;
    this.lazy = false;
    // 通过切点和方法信息得到一个Advice对象,提醒:当前是在Advisor内部了
    this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
}

instantiateAdvice()方法实现如下:

通过getAdvice()去生成一个Advisor

private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
   Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
         this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
   return (advice != null ? advice : EMPTY_ADVICE);
}

在ReflectiveAspectJAdvisorFactory的getAdvice()方法中,会去解析方法上的注解,然后根据注解类型,生成对应的Advisor

public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
      MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {

   Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
   validate(candidateAspectClass);

   // 拿到当前candidateAdviceMethod方法上的注解信息
   AspectJAnnotation<?> aspectJAnnotation =
         AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
   if (aspectJAnnotation == null) {
      return null;
   }
	……

   AbstractAspectJAdvice springAdvice;

   // 按不同的注解类型得到不同的Advice
   switch (aspectJAnnotation.getAnnotationType()) {
      case AtPointcut:
         return null;
      case AtAround:
         springAdvice = new AspectJAroundAdvice(
               candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
         break;
      case AtBefore:
         springAdvice = new AspectJMethodBeforeAdvice(
               candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
         break;
      case AtAfter:
         springAdvice = new AspectJAfterAdvice(
               candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
         break;
      case AtAfterReturning:
         springAdvice = new AspectJAfterReturningAdvice(
               candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
         AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
         if (StringUtils.hasText(afterReturningAnnotation.returning())) {
            springAdvice.setReturningName(afterReturningAnnotation.returning());
         }
         break;
      case AtAfterThrowing:
         springAdvice = new AspectJAfterThrowingAdvice(
               candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
         AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
         if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
            springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
         }
         break;
      default:
         throw new UnsupportedOperationException(
               "Unsupported advice type on method: " + candidateAdviceMethod);
   }


   return springAdvice;
}

2.3 筛选Advisor

通过canApply()筛选Advisor,筛选逻辑同上一篇文章《Spring AOP源码分析(中)》

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
   if (candidateAdvisors.isEmpty()) {
      return candidateAdvisors;
   }
   boolean hasIntroductions = !eligibleAdvisors.isEmpty();
   for (Advisor candidate : candidateAdvisors) {
      if (candidate instanceof IntroductionAdvisor) {
         // already processed
         continue;
      }
      if (canApply(candidate, clazz, hasIntroductions)) {
         eligibleAdvisors.add(candidate);
      }
   }
   return eligibleAdvisors;
}

先判断类是否匹配,再判断类中的方法是否匹配

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
   Assert.notNull(pc, "Pointcut must not be null");
   // 判断targetClass是不是和当前Pointcut匹配

   // 先判断类
   if (!pc.getClassFilter().matches(targetClass)) {
      return false;
   }

   MethodMatcher methodMatcher = pc.getMethodMatcher();
   if (methodMatcher == MethodMatcher.TRUE) {
      // No need to iterate the methods if we're matching any method anyway...
      return true;
   }
	……
   Set<Class<?>> classes = new LinkedHashSet<>();
   if (!Proxy.isProxyClass(targetClass)) {
      classes.add(ClassUtils.getUserClass(targetClass));
   }
   classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

   for (Class<?> clazz : classes) {
      Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
      for (Method method : methods) {
         if (introductionAwareMethodMatcher != null ?
               introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
               // 在判断方法是否匹配
               methodMatcher.matches(method, targetClass)) {
            return true;
         }
      }
   }

   return false;
}

2.4 生成代理对象

如果找到匹配的Advisor,将当前Bean封装成SingletonTargetSource,调用createProxy生成代理对象并返回

Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
   // advisedBeans记录了某个Bean已经进行过AOP了
   this.advisedBeans.put(cacheKey, Boolean.TRUE);
   Object proxy = createProxy(
         bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
   this.proxyTypes.put(cacheKey, proxy.getClass());
   return proxy;
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/112147.html

(0)
Java光头强的头像Java光头强

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!