5

Spring AOP 源码分析:获得通知

 3 years ago
source link: https://www.diguage.com/post/spring-aop-get-advices/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

注册 Advice(通知/增强)

请根据 Spring AOP 源码分析:入门 中提到的关键方法入口处,打上断点,开始调试。

首先,需要明确一点的是:对于切面(使用 @Aspect 注解标注过的类)在 Spring 容器中,也是被统一f封装为 BeanDefinition 实例的,也需要通过一个方式,将其注册到 Spring 容器中。比如,就像 示例代码 那样,通过 ImportSelector 方式,使用类名,将其注册到容器中。这样,就可以利用 Spring 容器对 Bean 的 API 来统一处理了。

Advice(通知/增强)几乎是在意想不到的地方完成注册的:在第一次调用 AbstractAutoProxyCreator#postProcessBeforeInstantiation 方法时,通过 AspectJAwareAdvisorAutoProxyCreator#shouldSkip 方法,完成了切面的注册。下面,我们对这个过程抽丝剥茧,逐步分析。

先来看看 findCandidateAdvisors 方法:

AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
@Override
protected List<Advisor> findCandidateAdvisors() {
  // Add all the Spring advisors found according to superclass rules.
  //当使用注解方式配置AOP的时候并不是丢弃了对XML配置的支持
  //在这里调用父类方法加载配置文件中的AOP声明
  List<Advisor> advisors = super.findCandidateAdvisors();
  // Build Advisors for all AspectJ aspects in the bean factory.
  if (this.aspectJAdvisorsBuilder != null) {
    advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
  }
  return advisors;
}

查找 XML 配置的 Advisor

正如上面注释所示,会先通过 super.findCandidateAdvisors() 先获取父类方法加载的切面声明:

AbstractAdvisorAutoProxyCreator#findCandidateAdvisors
protected List<Advisor> findCandidateAdvisors() {
  Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
  return this.advisorRetrievalHelper.findAdvisorBeans();
}

直接看 advisorRetrievalHelper.findAdvisorBeans() 方法:

BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans
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!
    // 在 beanNamesForTypeIncludingAncestors 方法中,通过遍历所有 Bean 名称来选取合适的对对象,
    // 查找的是通过 XML 配置的 <aop:advisor/> Bean。并不会把 @Aspect 标注的类给选出来。
    advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
        this.beanFactory, Advisor.class, true, false);
    this.cachedAdvisorBeanNames = advisorNames;
  }
  if (advisorNames.length == 0) {
    return new ArrayList<>();
  }

  List<Advisor> advisors = new ArrayList<>();
  for (String name : advisorNames) {
    if (isEligibleBean(name)) {
      if (this.beanFactory.isCurrentlyInCreation(name)) {
        if (logger.isTraceEnabled()) {
          logger.trace("Skipping currently created advisor '" + name + "'");
        }
      }
      else {
        try {
          advisors.add(this.beanFactory.getBean(name, Advisor.class));
        }
        catch (BeanCreationException ex) {
          Throwable rootCause = ex.getMostSpecificCause();
          if (rootCause instanceof BeanCurrentlyInCreationException) {
            BeanCreationException bce = (BeanCreationException) rootCause;
            String bceBeanName = bce.getBeanName();
            if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
              if (logger.isTraceEnabled()) {
                logger.trace("Skipping advisor '" + name +
                    "' with dependency on currently created bean: " + ex.getMessage());
              }
              // Ignore: indicates a reference back to the bean we're trying to advise.
              // We want to find advisors other than the currently created bean itself.
              continue;
            }
          }
          throw ex;
        }
      }
    }
  }
  return advisors;
}

这里通过 BeanFactoryUtils#beanNamesForTypeIncludingAncestors(ListableBeanFactory, Class<?>, boolean, boolean) 方法来查找 Advisor。整个过程,就是针对 BeanFactory 递归调用其父 BeanFactory,遍历所有的 Bean 名称,查找类型为 Advisor 的 Bean 名称,然后调用 beanFactory.getBean(name, Advisor.class),来获得对应的 Advisor Bean 并返回。

上面介绍了查找 XML 配置的 Advisor 过程。

查找通过注解配置的 Advisor

我们回到 AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors 方法中, BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors

BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors
public List<Advisor> buildAspectJAdvisors() {
  List<String> aspectNames = this.aspectBeanNames;

  if (aspectNames == null) {
    synchronized (this) {
      aspectNames = this.aspectBeanNames;
      if (aspectNames == null) {
        List<Advisor> advisors = new ArrayList<>();
        aspectNames = new ArrayList<>();
        //获取所有的beanName
        String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
            this.beanFactory, Object.class, true, false);
        //循环所有的beanName找出对应的增强方法
        for (String beanName : beanNames) {
          //不合法的bean则略过,由子类定义规则,默认返回true
          if (!isEligibleBean(beanName)) {
            continue;
          }
          // 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.
          //获取对应的bean的类型
          Class<?> beanType = this.beanFactory.getType(beanName);
          if (beanType == null) {
            continue;
          }
          //如果存在Aspect注解
          if (this.advisorFactory.isAspect(beanType)) {
            aspectNames.add(beanName);
            AspectMetadata amd = new AspectMetadata(beanType, beanName);
            if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
              MetadataAwareAspectInstanceFactory factory =
                  new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
              //解析标记AspectJ注解中的增强方法
              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);
            }
            else {
              // Per target or per this.
              if (this.beanFactory.isSingleton(beanName)) {
                throw new IllegalArgumentException("Bean with name '" + beanName +
                    "' is a singleton, but aspect instantiation model is not singleton");
              }
              MetadataAwareAspectInstanceFactory factory =
                  new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
              this.aspectFactoryCache.put(beanName, factory);
              advisors.addAll(this.advisorFactory.getAdvisors(factory));
            }
          }
        }
        this.aspectBeanNames = aspectNames;
        return advisors;
      }
    }
  }

  if (aspectNames.isEmpty()) {
    return Collections.emptyList();
  }
  List<Advisor> advisors = new ArrayList<>();
  for (String aspectName : aspectNames) {
    List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
    if (cachedAdvisors != null) {
      advisors.addAll(cachedAdvisors);
    }
    else {
      MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
      advisors.addAll(this.advisorFactory.getAdvisors(factory));
    }
  }
  return advisors;
}

这里的逻辑比上面要简单清晰好多:查找出所有的 Bean 名称,然后选出类型标注了 @Aspect 注解的 Bean 类型,把 Bean 名称添加到 BeanFactoryAspectJAdvisorsBuilder#aspectBeanNames 实例变量中;根据类型信息,使用反射针对符合添加的方法,构建 Advisor 对象(实现类为 InstantiationModelAwarePointcutAdvisorImpl),然后将其加入到 BeanFactoryAspectJAdvisorsBuilder#advisorsCache 变量中。

值得注意的是根据通知的类型,创建不同的 Advice 对象,也是在上面的这个过程中,在 ReflectiveAspectJAdvisorFactory#getAdvice 方法中完成的。

经过上面的处理,所有对应的 Advice(通知/增强)都会被查找出来。接下来,我们看一看如何针对特定的 Bean 选择出合适的 Advice(通知/增强)的。

这里说“注册”其实意思不太正确。 Advice(通知/增强)没有什么注册一说,它只是被解析后缓存了起来。下次再使用时,就不需要解析了。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK