「Spring-Aop」源码分析四:Aop源码解析

众所周知,Aop各种切面肯定是通过创建代理(Aop的各种基本概念各位听都应该听会了,这里就不多赘述了)。但是问题随之产生了,我们已经分析了普通bean的解析及创建,aop是在哪边创建代理对象的呢,怎么匹配切点的呢。这篇也是围绕这两个问题进行分析。动态代理的分析上一篇已经分析完了,感兴趣的可以看一下。传送门

本篇研究的问题

  • 代理对象的创建
  • 匹配切点

    测试代码

    @Aspect
    class AdviceUsingThisJoinPoint {
    
      private String lastEntry = "";
    
      public String getLastMethodEntered() {
          return this.lastEntry;
      }
    
      @Pointcut("execution(int *.getAge())")
      public void methodExecution() {
      }
    
      @Before("methodExecution()")
      public void entryTrace(JoinPoint jp) {
          this.lastEntry = jp.toString();
          System.out.println(this.lastEntry);
      }
    }
    
    public class TestBean implements BeanNameAware, BeanFactoryAware, ITestBean, IOther, Comparable {
    //多余部分删除了
      private String name;
    
      private int age;
    
      public TestBean() {
      }
    
      public TestBean(String name) {
          this.name = name;
      }
      
      @Override
      public String getName() {
          return name;
      }
    
      @Override
      public void setName(String name) {
          this.name = name;
      }
    
      @Override
      public int getAge() {
          return age;
      }
    
      @Override
      public void setAge(int age) {
          this.age = age;
      }
    
      /**
       * @see org.springframework.beans.testfixture.beans.ITestBean#exceptional(Throwable)
       */
      @Override
      public void exceptional(Throwable t) throws Throwable {
          if (t != null) {
              throw t;
          }
      }
    
      @Override
      public void unreliableFileOperation() throws IOException {
          throw new IOException();
      }
      /**
       * @see org.springframework.beans.testfixture.beans.ITestBean#returnsThis()
       */
      @Override
      public Object returnsThis() {
          return this;
      }
    
      /**
       * @see org.springframework.beans.testfixture.beans.IOther#absquatulate()
       */
      @Override
      public void absquatulate() {
      }
    
      @Override
      public int haveBirthday() {
          return age++;
      }
    
      @Override
      public boolean equals(Object other) {
          if (this == other) {
              return true;
          }
          if (other == null || !(other instanceof TestBean)) {
              return false;
          }
          TestBean tb2 = (TestBean) other;
          return (ObjectUtils.nullSafeEquals(this.name, tb2.name) && this.age == tb2.age);
      }
    
      @Override
      public int hashCode() {
          return this.age;
      }
    
      @Override
      public int compareTo(Object other) {
          if (this.name != null && other instanceof TestBean) {
              return this.name.compareTo(((TestBean) other).getName());
          }
          else {
              return 1;
          }
      }
    
      @Override
      public String toString() {
          return this.name;
      }
    
    }
    
    
    
    
    
      
    
      
    
      
          
          
      
    
    
      @Test
      public void testAdviceUsingJoinPoint() {
          ClassPathXmlApplicationContext bf = newContext("usesJoinPointAspect.xml");
    
          ITestBean adrian1 = (ITestBean) bf.getBean("adrian");
          adrian1.getAge();
          adrian1.getDoctor();
          AdviceUsingThisJoinPoint aspectInstance = (AdviceUsingThisJoinPoint) bf.getBean("aspect");
          assertThat(aspectInstance.getLastMethodEntered().indexOf("TestBean.getAge())") != 0).isTrue();
      }

    源码分析

    创建代理对象的入口为AbstractAutoProxyCreator#postProcessBeforeInstantiation,可以看出核心方法为getAdvicesAndAdvisorsForBean,后面就是创建代理对象了

    @Override
      public Object postProcessBeforeInstantiation(Class beanClass, String beanName) {
          Object cacheKey = getCacheKey(beanClass, beanName);
    
          if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
              if (this.advisedBeans.containsKey(cacheKey)) {
                  return null;
              }
              if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
                  this.advisedBeans.put(cacheKey, Boolean.FALSE);
                  return null;
              }
          }
    
          // Create proxy here if we have a custom TargetSource.
          // Suppresses unnecessary default instantiation of the target bean:
          // The TargetSource will handle target instances in a custom fashion.
          TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
          if (targetSource != null) {
              if (StringUtils.hasLength(beanName)) {
                  this.targetSourcedBeans.add(beanName);
              }
              Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
              Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
              this.proxyTypes.put(cacheKey, proxy.getClass());
              return proxy;
          }
    
          return null;
      }

    此方法是获取对应的Advisor

      protected List findEligibleAdvisors(Class beanClass, String beanName) {
          List candidateAdvisors = findCandidateAdvisors();//获取候选Advisor
          List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);//获取适用于bean的Advisor: 例如Pointcut匹配
          extendAdvisors(eligibleAdvisors);//特殊处理
          if (!eligibleAdvisors.isEmpty()) {
              eligibleAdvisors = sortAdvisors(eligibleAdvisors);//排序
          }
          return eligibleAdvisors;
      }

    findCandidateAdvisors最终会调用buildAspectJAdvisors获取对应的Advisor
    第一次进入会找到@Aspect定义过的方法,生成对应的Advisor(封装了Advice),后续就会从缓存中取

    public List buildAspectJAdvisors() {
          List aspectNames = this.aspectBeanNames;
    
          if (aspectNames == null) {
              synchronized (this) {
                  aspectNames = this.aspectBeanNames;//并发问题
                  if (aspectNames == null) {
                      List advisors = new ArrayList<>();
                      aspectNames = new ArrayList<>();
                      String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(//
                              this.beanFactory, Object.class, true, false);
                      for (String beanName : beanNames) {
                          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.
                          Class beanType = this.beanFactory.getType(beanName, false);
                          if (beanType == null) {
                              continue;
                          }
                          if (this.advisorFactory.isAspect(beanType)) {//是否为@Aspect修饰的bean
                              aspectNames.add(beanName);
                              AspectMetadata amd = new AspectMetadata(beanType, beanName);
                              if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                                  MetadataAwareAspectInstanceFactory factory =
                                          new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                                  List classAdvisors = this.advisorFactory.getAdvisors(factory);//生成Adivsor
                                  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 advisors = new ArrayList<>();
          for (String aspectName : aspectNames) {
              List 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;
      }

    上面获取到了所有的Advisor集合接下来就是获取到匹配的Advisor

      public static List findAdvisorsThatCanApply(List candidateAdvisors, Class clazz) {
          if (candidateAdvisors.isEmpty()) {
              return candidateAdvisors;
          }
          List eligibleAdvisors = new ArrayList<>();
          for (Advisor candidate : candidateAdvisors) {
              if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
                  eligibleAdvisors.add(candidate);
              }
          }
          boolean hasIntroductions = !eligibleAdvisors.isEmpty();
          for (Advisor candidate : candidateAdvisors) {//遍历Advisor找到匹配的
              if (candidate instanceof IntroductionAdvisor) {
                  // already processed
                  continue;
              }
              if (canApply(candidate, clazz, hasIntroductions)) {
                  eligibleAdvisors.add(candidate);
              }
          }
          return eligibleAdvisors;
      }

    具体匹配是在org.springframework.aop.support.AopUtils#canApply(org.springframework.aop.Pointcut, java.lang.Class, boolean)方法中判断,先判断类是否匹配再判断方法是否匹配

      public static boolean canApply(Pointcut pc, Class targetClass, boolean hasIntroductions) {
          Assert.notNull(pc, "Pointcut must not be null");
          if (!pc.getClassFilter().matches(targetClass)) {//匹配class
              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;
          }
    
          IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
          if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
              introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
          }
    
          Set> 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;
      }

    后面就会创建代理对象,根据有无接口为主要条件判断是JDK代理还是Cglib动态代理,这两个上篇已经讲过了,这里就不过多赘述了

      @Override
      public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
          if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
              Class targetClass = config.getTargetClass();
              if (targetClass == null) {
                  throw new AopConfigException("TargetSource cannot determine target class: " +
                          "Either an interface or a target is required for proxy creation.");
              }
              if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                  return new JdkDynamicAopProxy(config);
              }
              return new ObjenesisCglibAopProxy(config);
          }
          else {
              return new JdkDynamicAopProxy(config);
          }
      }

    总结

    先扫描所有@Aspect注解的对象,封装成Advisor对象,缓存起来,创建对象的时候循环判断是否匹配。

    随便说两句

    至此SpringIoC和Aop的部分已经全部分析完了。
    前面几篇也来个传送门
    「Spring-IoC」源码分析一获取bean信息
    「Spring-IoC」源码分析二依赖注入&依赖循环
    「Spring-Aop」源码分析三:JDK动态代理&Cglib

    你可能感兴趣的:(spring源码分析)