Spring之AOP源码分析

Spring AOP

  • 它基于动态代理来实现。 如果使用接口,用JDK提供给动态代理来实现,如果没有接口,使用CGLIB实现。
  • Spring 3.2以后,spring-core直接把CGLIB和ASM的源码包括进来。
  • Spring AOP需要依赖于IOC容器来管理。
  • Spring提供了AspectJ的支持,但只用到了切点解析和匹配。

源码

开启aop切面

spring通过@EnableAspectJAutoProxy开启aop切面,在注解类上面发现@Import(AspectJAutoProxyRegistrar.class),AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar,所以他会通过registerBeanDefinitions方法为我们容器导入beanDefinition。 image.png
image.png
image.png

解析切面

image.png
image.png
第一次调用bean的后置处理器回去进行切面的解析。具体解析类是AbstractAutoProxyCreator,它实现了InstantiationAwareBeanPostProcessor。进入postProcessBeforeInstantiation方法。 image.png
判断是否应该跳过。真正的解析是在shouldSkip中。 image.png
image.png
进入findCandidateAdvisors的重写方法。 image.png
调用super.findCandidateAdvisors(),去查找实现了Advisor接口的切面类。

public List<Advisor> findAdvisorBeans() {

   /**
    * 探测器字段缓存中cachedAdvisorBeanNames 是用来保存我们的Advisor全类名
    * 会在第一个单实例bean的中会去把这个advisor名称解析出来
    */
   String[] advisorNames = this.cachedAdvisorBeanNames;
   if (advisorNames == null) {
      /**
       * 去我们的容器中获取到实现了Advisor接口的实现类
       * 而我们的事务注解@EnableTransactionManagement 导入了一个叫ProxyTransactionManagementConfiguration配置类
       * 而在这个配置类中配置了
       * @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
         @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
         public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor();
         然后把他的名字获取出来保存到 本类的属性变量cachedAdvisorBeanNames中
       */
      advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
            this.beanFactory, Advisor.class, true, false);
      this.cachedAdvisorBeanNames = advisorNames;
   }
   //若在容器中没有找到,直接返回一个空的集合
   if (advisorNames.length == 0) {
      return new ArrayList<>();
   }

   List<Advisor> advisors = new ArrayList<>();
   //ioc容器中找到了我们配置的BeanFactoryTransactionAttributeSourceAdvisor
   for (String name : advisorNames) {
      //判断他是不是一个合适的 是我们想要的
      if (isEligibleBean(name)) {
         //BeanFactoryTransactionAttributeSourceAdvisor是不是正在创建的bean
         if (this.beanFactory.isCurrentlyInCreation(name)) {
            if (logger.isDebugEnabled()) {
               logger.debug("Skipping currently created advisor '" + name + "'");
            }
         }
         //不是的话
         else {
            try {
               //显示的调用getBean方法方法创建我们的BeanFactoryTransactionAttributeSourceAdvisor返回去
               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.isDebugEnabled()) {
                        logger.debug("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;
}
复制代码

调用buildAspectJAdvisors去查找注解方式的切面类。

/**
 * 去容器中获取到所有的切面信息保存到缓存中
 * @return the list of {@link org.springframework.aop.Advisor} beans
 * @see #isEligibleBean
 */
public List<Advisor> buildAspectJAdvisors() {
   /**
    * 用于保存切面的名称,该地方aspectNames 是我们的类级别的缓存,用户缓存已经解析出来的切面信息
    */
   List<String> aspectNames = this.aspectBeanNames;
   // 缓存字段aspectNames没有值 会在第一个单例执行后置处理器(AnnotationAwareAspectJAutoProxyCreator注册之后)的时候就会触发解析切面的操作
   if (aspectNames == null) {
      // 加上同步锁, 防止多线程同时加载Aspect
      synchronized (this) {
         aspectNames = this.aspectBeanNames;
         //做了双重检查加锁
         if (aspectNames == null) {
            // 保存所有通知的集合
            List<Advisor> advisors = new ArrayList<>();
            // 保存切面的名称的集合
            aspectNames = new ArrayList<>();
            /**
             * aop功能中在这里传入的是Object.class,代表去容器中获取到所有的组件的名称,然后再经过
             * 一一的进行遍历,这个过程是十分的消耗性能的,所以说spring会再这里加入了保存切面信息的缓存。
             * 但是事务功能不一样,事务模块的功能是直接去容器中获取Advisor类型的,选择范围小,且不消耗性能。所以
             * spring在事务模块中没有加入缓存来保存我们的事务相关的advisor
             */
            String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                  this.beanFactory, Object.class, true, false);
            //遍历我们从IOC容器中获取处的所有bean的名称
            for (String beanName : beanNames) {
               if (!isEligibleBean(beanName)) {
                  continue;
               }
               //通过beanName去容器中获取到对应class对象
               Class<?> beanType = this.beanFactory.getType(beanName);
               if (beanType == null) {
                  continue;
               }
               //根据class对象判断是不是切面 即判断类上面是否有Aspect注解且不是ajc$开头的文件。
               if (this.advisorFactory.isAspect(beanType)) {
                  //是切面类
                  //加入到缓存中
                  aspectNames.add(beanName);
                  //把beanName和class对象构建成为一个AspectMetadata
                  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 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;
}
复制代码

getAdvisors方法

@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
   //获取我们的标记为Aspect的类
   Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
   //获取我们的切面类的名称
   String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
   //校验我们的切面类
   validate(aspectClass);

   //我们使用的是包装模式来包装我们的MetadataAwareAspectInstanceFactory 构建为MetadataAwareAspectInstanceFactory
   MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
         new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);

   List<Advisor> advisors = new ArrayList<>();
   //获取到切面类中的所有方法,但是该方法不会解析标注了@PointCut注解的方法
   for (Method method : getAdvisorMethods(aspectClass)) {
      //挨个去解析我们切面中的方法 详细看下面
      Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
      if (advisor != null) {
         advisors.add(advisor);
      }
   }

   // If it's a per target aspect, emit the dummy instantiating aspect.
   if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
      Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
      advisors.add(0, instantiationAdvisor);
   }

   // Find introduction fields.
   for (Field field : aspectClass.getDeclaredFields()) {
      Advisor advisor = getDeclareParentsAdvisor(field);
      if (advisor != null) {
         advisors.add(advisor);
      }
   }

   return advisors;
}
复制代码

getAdvisor方法

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

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

   // 获得当前通知的 切点表达式
   AspectJExpressionPointcut expressionPointcut = getPointcut(
         candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
   if (expressionPointcut == null) {
      return null;
   }
   // 将切点表达式、 和通知  封装到InstantiationModelAwarePointcutAdvisorImpl对象中
   return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
         this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
复制代码

getPointcut方法

private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
   // 找到aspectJ的注解:
   // @Pointcut  @Around @Before @After  @AfterReturning  @AfterThrowing
   AspectJAnnotation<?> aspectJAnnotation =
         AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
   // 没有注解那肯定忽略
   if (aspectJAnnotation == null) {
      return null;
   }

   AspectJExpressionPointcut ajexp =
         new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
   ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
   if (this.beanFactory != null) {
      ajexp.setBeanFactory(this.beanFactory);
   }
   return ajexp;
}
复制代码

猜你喜欢

转载自juejin.im/post/7033016689923096584