家喻户晓,Aop各种切面必定是通过创立代理(Aop的各种基本概念各位听都应该听会了,这里就不多赘述了)。然而问题随之产生了,咱们曾经剖析了一般bean的解析及创立,aop是在哪边创立代理对象的呢,怎么匹配切点的呢。这篇也是围绕这两个问题进行剖析。动静代理的剖析上一篇曾经剖析完了,感兴趣的能够看一下。传送门

本篇钻研的问题

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

    测试代码

    @Aspectclass 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<Object> {//多余局部删除了  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;  }}
    <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "https://www.springframework.org/dtd/spring-beans-2.0.dtd"><beans>  <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>  <bean id="aspect" class="org.springframework.aop.aspectj.autoproxy.AdviceUsingThisJoinPoint"/>  <bean id="adrian" class="org.springframework.beans.testfixture.beans.TestBean" scope="prototype">      <property name="name" value="adrian"/>      <property name="age" value="34"/>  </bean></beans>
      @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<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {      List<Advisor> candidateAdvisors = findCandidateAdvisors();//获取候选Advisor      List<Advisor> 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<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<>();                  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<Advisor> 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<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;  }

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

      public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {      if (candidateAdvisors.isEmpty()) {          return candidateAdvisors;      }      List<Advisor> 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<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;  }

    前面就会创立代理对象,依据有无接口为次要条件判断是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