源码揭秘!Spring中AOP编程实现原理!(三)被切面类创建流程(1)

231 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第9天,点击查看活动详情

源码揭秘系列|目录

源码揭秘! Spring IOC之Autowired注解!
源码揭秘! Spring中Bean扫描的原理!
源码揭秘! Spring和Mybatis整合的原理!
源码揭秘! Spring中AOP编程实现原理! (一) 准备动作
源码揭秘! Spring中AOP编程实现原理! (二) Advice类的注册流程

前言

在上一章节中,讲到了我们Advice类在postProcessBeforeInstantiation方法中是如何操作的,由于Bean是Advice的,所以下面代码的第一个条件就进入了。 image.png 今天这篇文章来看下被注入类的一个床就流程是什么样的。

正式开始

在注入类中,isInfrastructureClass方法肯定为false,所以此时会进入shouldSkip方法。

shouldSkip方法

Abstract中的shouldSkip方法是下面这样。 image.png 由于子类有重写方法,所以此时调用的方法应该是在AspectJAwareAdvisorAutoProxyCreator类中,代码如下。

@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
   // TODO: Consider optimization by caching the list of the aspect names
   // TODO: 考虑通过缓存方面名称列表进行优化
   List<Advisor> candidateAdvisors = findCandidateAdvisors();
   for (Advisor advisor : candidateAdvisors) {
      if (advisor instanceof AspectJPointcutAdvisor &&
            ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
         return true;
      }
   }
   return super.shouldSkip(beanClass, beanName);
}

首先看下下面的第一个方法findCandidateAdvisors(),根据方法字面意思查找候选的Advisors。这里要进去看一下。

findCandidateAdvisors

这个方法在AnnotationAwareAspectJAutoProxyCreator类中有重写。

@Override
protected List<Advisor> findCandidateAdvisors() {
   // Add all the Spring advisors found according to superclass rules.
   // 添加根据超类规则找到的所有 Spring 顾问。
   List<Advisor> advisors = super.findCandidateAdvisors();
   // Build Advisors for all AspectJ aspects in the bean factory.
   // 为 bean 工厂中的所有 AspectJ 方面构建顾问。
   if (this.aspectJAdvisorsBuilder != null) {
      advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
   }
   return advisors;
}

该方法构成比较简单,第一个是调用了父类的findCandidateAdvisors方法,随后使用aspectJAdvisorsBuilder去构建,然后塞入advisors中。

这里先看一下父类的findCandidateAdvisors方法。

父类的findCandidateAdvisors方法

image.png 这里代码接着往下追。

public List<Advisor> findAdvisorBeans() {
   // Determine list of advisor bean names, if not cached already.
   // 确定顾问 bean 名称列表(如果尚未缓存)。
   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!
      // 不要在此处初始化 FactoryBeans:
      // 我们需要保留所有常规 bean未初始化让自动代理创建者适用于他们!
      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)) {
            // ... log
         }
         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)) {
                     // ... log
                     continue;
                  }
               }
               throw ex;
            }
         }
      }
   }
   return advisors;
}

这个方法开始有两个If,第一个If用来判断,判断缓存的advior为空的话,要为其初始化,也就是从BeanFactory获取一下祖先类中包含Adviosr.class的BeanName。

第二个If是判断如果拿到为空的话就返回一个空的ArrayList。

接下来就是遍历刚刚获取到的BeanName,然后判断遍历到的Bean是否正在创建,这里通常情况下,是为False的,随后走入Else逻辑,也就是像advisors中添加当前的Bean。遍历完后返回advisors。

由于我们前没有设置这些Advisor,所以这个方法不出意外是返回一个空的ArrayList。 image.png 打断点查看后,不出所料。

findCandidateAdvisors剩余的逻辑

// Build Advisors for all AspectJ aspects in the bean factory.
// 为bean factory中的所有AspectJ方面构建 Advisors。
if (this.aspectJAdvisorsBuilder != null) {
   advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;

aspectJAdvisorsBuilder此处是不等于null。因为我们的BeanFactory时,创建的DefaultListableBeanFactory,会调用这里的一个initBeanFacotry方法。给这个属性赋值。

buildAspectJAdvisors 方法

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

   if (aspectNames == null) {
      // ... 
   }

   if (aspectNames.isEmpty()) {
      return Collections.emptyList();
   }
   List<Advisor> advisors = new ArrayList<>();
   for (String aspectName : aspectNames) {
      // ...
   }
   return advisors;
}

先看下这个方法的大体结构,方法刚开始,创建了一个aspectNames变量,随后判断这个Names是否为空,为Null的话,进入If中,猜测是初始化的逻辑。

随后遍历了这个Name,应该是把aspectName具像化了。最后返回了advisors。

第一个If中的代码
if (aspectNames == null) {
   List<Advisor> advisors = new ArrayList<>();
   aspectNames = new ArrayList<>();
   String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
         this.beanFactory, Object.class, true, false);
   for (String beanName : beanNames) {
      // ...
      // 不是Aspect类会进行continue操作。
      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);
            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
            }
            MetadataAwareAspectInstanceFactory factory =
                  new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
            this.aspectFactoryCache.put(beanName, factory);
            advisors.addAll(this.advisorFactory.getAdvisors(factory));
         }
      }
   }
   this.aspectBeanNames = aspectNames;
   return advisors;
}

看这一片代码,跳过一些检验的过程。把这个Beanname加入aspectNames中。然后获取Aspect元数据。然后进行判断,这里会进入If。

根据BeanName创建了一个MetadataAwareAspectInstanceFactory。因为这个里面会有Aspect的Metadata。所以这里可以获取到当前的Advisors,从这里可以知道了,Advisors其实指的就是每一个切入点的指标。随后把指标放入了AdvisorsCache中。然后返回Advisors数据。 image.png 后续的代码其实意思相同,因为等于null时,会把数据放入缓存了,所以不等于null时的场景就是,从缓存中获取,然后会出去。

should方法剩余的逻辑

image.png 这里就是判断一下,当前beanName是否和刚刚获取到的切入点的操作类的Name一致,如果一致的话,返回True。不一致返回False。剩余很明显返回false。

BeforeInstantiation方法剩余逻辑

image.png 在这个地方的代码中,可以看到创建代理了。有几个关键点要说明一下。
specificInterceptors变量赋值了Advices。也就是切入点集合。这里转换了数组。
可以看到的是,在下方的createProxy方法中,放入了这个变量。

告一段落

往后面写文章字数有点多了,此篇文章先到这里,在下一篇中继续讲解。

都看到这了,点个赞再走呗,宝~

结束语

写文章的目的是为了帮助自己巩固知识,写的不好或者错误的地方可以在评论区指出。如果您看了文章觉得对您有所帮助可以点个赞,如果发现有些问题产生了疑惑,或者不明白的可以评论、加我微信,一定知无不言。当然也希望和大家交个朋友,相互学习。