【小家Spring】Spring AOP的核心类:AbstractAdvisorAutoProxy自动代理创建器深度剖析(AnnotationAwareAspectJAutoProxyCreator)(下)

简介: 【小家Spring】Spring AOP的核心类:AbstractAdvisorAutoProxy自动代理创建器深度剖析(AnnotationAwareAspectJAutoProxyCreator)(下)

AbstractAdvisorAutoProxyCreator 这是另一类自动代理方式


它是Spring2.0提供的(2.0版本2006年才发布哦~~~)

顾名思义,它和Advisor有关(只有被切入的类,才会给它创建一个代理类),它的核心方法是实现了父类的:getAdvicesAndAdvisorsForBean来获取Advisor们

public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {
  // 这个类是重点,后面会详细介绍
  @Nullable
  private BeanFactoryAdvisorRetrievalHelper advisorRetrievalHelper;
  // 重写了setBeanFactory方法,事需要保证bean工厂必须是ConfigurableListableBeanFactory
  @Override
  public void setBeanFactory(BeanFactory beanFactory) {
    super.setBeanFactory(beanFactory);
    if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
      throw new IllegalArgumentException(
          "AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
    }
    // 就这一句话:this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory)
    // 对Helper进行初始化,找advisor最终事委托给他了的
    // BeanFactoryAdvisorRetrievalHelperAdapter继承自BeanFactoryAdvisorRetrievalHelper,为私有内部类,主要重写了isEligibleBean()方法,调用.this.isEligibleAdvisorBean(beanName)方法
    initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
  }
  // 这是复写父类的方法,也是实现代理方式。找到作用在这个Bean里面的切点方法
  // 当然 最终最终事委托给BeanFactoryAdvisorRetrievalHelper去做的
  @Override
  @Nullable
  protected Object[] getAdvicesAndAdvisorsForBean(
      Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
    // findEligibleAdvisors:显然这个是具体的实现方法了。
    // eligible:合格的  合适的
    List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
    if (advisors.isEmpty()) {
      return DO_NOT_PROXY;
    }
    return advisors.toArray();
  }
  // 找出合适的Advisor们~~~  主要分了下面几步
  protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    // 首先找出所有的候选的Advisors,(根据名字判断)实现见下面~~~~
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // 对上面找到的候选的Advisors们,进行过滤操作~~~  看看Advisor能否被用在Bean上(根据Advisor的PointCut判断)
    // 主要依赖于AopUtils.findAdvisorsThatCanApply()方法  在工具类讲解中有详细分析的
    // 逻辑简单概述为:看目标类是不是符合代理对象的条件,如果符合就把Advisor加到集合中,最后返回集合
    // 简单的说:它就是会根据ClassFilter和MethodMatcher等等各种匹配。(但凡只有有一个方法被匹配上了,就会给他创建代理类了)
    // 方法用的ReflectionUtils.getAllDeclaredMethods,**因此哪怕是私有方法,匹配上都会给创建的代理对象,这点务必要特别特别的注意**
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    //提供一个钩子。子类可以复写此方法  然后对eligibleAdvisors进行处理(增加/删除/修改等等)
    // AspectJAwareAdvisorAutoProxyCreator提供了实现
    extendAdvisors(eligibleAdvisors);
    // 如果最终还有,那就排序吧 
    if (!eligibleAdvisors.isEmpty()) {
      // 默认排序方式:AnnotationAwareOrderComparator.sort()排序  这个排序和Order接口有关~~~
      // 但是子类:AspectJAwareAdvisorAutoProxyCreator有复写此排序方法,需要特别注意~~~
      eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
  }
  // 找到候选的Advisor们~~~~   抽象类自己的实现,是直接把这件事委托给了advisorRetrievalHelper
  // 关于它的具体逻辑  后文问详细分析  毕竟属于核心逻辑
  // AnnotationAwareAspectJAutoProxyCreator对它有复写
  protected List<Advisor> findCandidateAdvisors() {
    Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
    return this.advisorRetrievalHelper.findAdvisorBeans();
  }
  // 判断给定的BeanName这个Bean,是否是合格的(BeanFactoryAdvisorRetrievalHelper里会用到这个属性)
  // 其中:DefaultAdvisorAutoProxyCreator和InfrastructureAdvisorAutoProxyCreator有复写
  protected boolean isEligibleAdvisorBean(String beanName) {
    return true;
  }
  // 此处复写了父类的方法,返回true了,表示
  @Override
  protected boolean advisorsPreFiltered() {
    return true;
  }
}


我们发现这个抽象类主要是提供getAdvicesAndAdvisorsForBean()这个方法的获取模版(虽然它没有提供抽象方法给子类去实现,但子类复写了protected方法,改变了一些默认行为。但是各个实现类都各有不同,现在我们看看实现:)


image.png


从简单到复杂,从不用到常用,现在分析分析这些实现类:


DefaultAdvisorAutoProxyCreator


打个比方:它就是BeanNameAutoProxyCreator的加强版。如果说BeanNameAutoProxyCreator就是步枪需要自己装配,DefaultAdvisorAutoProxyCreator就是自动步枪了,Spring可以完成自动匹配的工作了


一般,我们只需要这样配置即可

    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        return new DefaultAdvisorAutoProxyCreator();
    }
  // 还需要对应的Advisor(可以有多个~~)  从而给能够匹配上的创建代理对象了
    @Bean
    public NameMatchMethodPointcutAdvisor nameMatchMethodPointcutAdvisor() {
        NameMatchMethodPointcutAdvisor nameMatchMethodPointcutAdvisor = new NameMatchMethodPointcutAdvisor();
        //拦截到了HelloService#hello()方法,因此会给他创建代理对象
        nameMatchMethodPointcutAdvisor.addMethodName("*hello");
        // 请注意:此处虽然HelloController有个方法名叫helloGet,但是不会创建代理得。因为这在根容器里,这种情况不作用与子容器的Bean的
        nameMatchMethodPointcutAdvisor.addMethodName("helloGet"); 
        nameMatchMethodPointcutAdvisor.setAdvice(new MyMethodInteceptor());
        return nameMatchMethodPointcutAdvisor;
    }


这样它就会自动的去把Advisor匹配上的Bean进行代理掉。(不像BeanNameAutoProxyCreator还得手动指定BeanName,以及拦截器们)


一般都需要自己像容器注入自己的Advisor,比如NameMatchMethodPointcutAdvisor,否则它也不知道去代理谁嘛。只有被对应的Advisor匹配上的才会生成代理对象


它的源码很简单:它也是只复写了一个方法

  // Consider {@code Advisor} beans with the specified prefix as eligible, if activated.
  // 用到了前缀之类的。主要是考虑可以通过前缀匹配某一类Bean,而其他的Advisor我就不匹配了
  // 前缀的作用:进行分离匹配(而不是拿所有的Advisor~~)
  @Override
  protected boolean isEligibleAdvisorBean(String beanName) {
    if (!isUsePrefix()) {
      return true;
    }
    String prefix = getAdvisorBeanNamePrefix();
    return (prefix != null && beanName.startsWith(prefix));
  }



InfrastructureAdvisorAutoProxyCreator

Infrastructure:基础设施、基建


听这名字就知道,这是Spring给自己内部使用的一个自动代理创建器。这个类在@EnableTransactionManagement事务相关里会再次提到(它的AutoProxyRegistrar就是向容器注册了它),其实它的作用非常简单:主要是读取Advisor类,并对符合的bean进行二次代理

public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {
  ...
  // 没有其余多余代码 就这一个
  // bean工厂含有这个Bean,且这个Bean的Role是BeanDefinition.ROLE_INFRASTRUCTURE 系统内部用的  才返回true
  @Override
  protected boolean isEligibleAdvisorBean(String beanName) {
    return (this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) &&
        this.beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE);
  }
}


接下来两个实现就和AspectJ相关了~~~相对来说比较难啃一点


AspectJAwareAdvisorAutoProxyCreator


顾名思义,该类主要来处理AspectJ切面的。这也是当下最流行,也是功能最为强大的一种方式吧~~~


它对父类,做了如下几点扩展:


// @since 2.0
public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {
  // 默认的排序器,它就不是根据Order来了,而是根据@Afeter @Before类似的标注来排序
  private static final Comparator<Advisor> DEFAULT_PRECEDENCE_COMPARATOR = new AspectJPrecedenceComparator();
  // 核心逻辑:它重写了排序
  // 这个排序和`org.aspectj.util`提供的PartialOrder和PartialComparable有关 具体不详叙了
  // 这块排序算法还是比较复杂的,控制着最终的执行顺序~
  protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
    ...
  }
  // 这个就是对已有的Advisor做了一个扩展:
  // AspectJProxyUtils这个工具类只有这一个方法  (其实每次addAspect()的时候,都会调用此方法)
  // Capable:能干的  有才华的
  // 它的作用:(若存在AspectJ的Advice),就会在advisors的第一个位置加入`ExposeInvocationInterceptor.ADVISOR`这个advisor
  @Override
  protected void extendAdvisors(List<Advisor> candidateAdvisors) {
    AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
  }
  // 这个相当于:
  @Override
  protected boolean shouldSkip(Class<?> beanClass, String beanName) {
    List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // 这个相当于AspectJPointcutAdvisor的子类不要拦截、AspectJ切面自己自己的所有方法不要去拦截。。。
    for (Advisor advisor : candidateAdvisors) {
      if (advisor instanceof AspectJPointcutAdvisor &&
          ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
        return true;
      }
    }
    // 父类返回的false
    return super.shouldSkip(beanClass, beanName);
  }
  ...
}


ExposeInvocationInterceptor 的作用是用于暴露 MethodInvocation 对象到 ThreadLocal 中,其名字也体现出了这一点。如果其他地方需要当前的 MethodInvocation 对象,直接通过调用静态方法 ExposeInvocationInterceptor.currentInvocation 方法取出。那哪些地方会用到呢????

AspectJExpressionPointcut#matches就有用到~~


AnnotationAwareAspectJAutoProxyCreator


首先AnnotationAwareAspectJAutoProxyCreator它是AspectJAwareAdvisorAutoProxyCreator的子类。


然后从名字中可议看出,它和注解有关。因此其实我们的@EnableAspectJAutoProxy它导入的就是这个自动代理创建器去帮我们创建和AspectJ相关的代理对象的。这也是我们当下使用最为广泛的方式~

// @since 2.0
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
  @Nullable
  private List<Pattern> includePatterns;
  //唯一实现类:ReflectiveAspectJAdvisorFactory
  // 作用:基于@Aspect时,创建Spring AOP的Advice
  // 里面会对标注这些注解Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class的方法进行排序
  // 然后把他们都变成Advisor( getAdvisors()方法 )
  @Nullable
  private AspectJAdvisorFactory aspectJAdvisorFactory;
  //该工具类用来从bean容器,也就是BeanFactory中获取所有使用了@AspectJ注解的bean
  //就是这个方法:aspectJAdvisorsBuilder.buildAspectJAdvisors()
  @Nullable
  private BeanFactoryAspectJAdvisorsBuilder aspectJAdvisorsBuilder;
  // 很显然,它还支持我们自定义一个正则的模版
  // isEligibleAspectBean()该方法使用此模版,从而决定使用哪些Advisor
  public void setIncludePatterns(List<String> patterns) {
    this.includePatterns = new ArrayList<>(patterns.size());
    for (String patternText : patterns) {
      this.includePatterns.add(Pattern.compile(patternText));
    }
  }
  // 可以自己实现一个AspectJAdvisorFactory  否则用默认的ReflectiveAspectJAdvisorFactory
  public void setAspectJAdvisorFactory(AspectJAdvisorFactory aspectJAdvisorFactory) {
    Assert.notNull(aspectJAdvisorFactory, "AspectJAdvisorFactory must not be null");
    this.aspectJAdvisorFactory = aspectJAdvisorFactory;
  }
  // 此处一定要记得调用:super.initBeanFactory(beanFactory);
  @Override
  protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    super.initBeanFactory(beanFactory);
    if (this.aspectJAdvisorFactory == null) {
      this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
    }
    this.aspectJAdvisorsBuilder = new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
  }
  // 拿到所有的候选的advisor们。请注意:这里没有先调用了父类的super.findCandidateAdvisors()  去容器里找出来一些
  // 然后,然后自己又通过aspectJAdvisorsBuilder.buildAspectJAdvisors()  解析@Aspect的方法得到一些Advisor
  @Override
  protected List<Advisor> findCandidateAdvisors() {
    List<Advisor> advisors = super.findCandidateAdvisors();
    if (this.aspectJAdvisorsBuilder != null) {
      advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
    }
    return advisors;
  }
  // 加了中类型   如果该Bean自己本身就是一个@Aspect, 那也认为是基础主键,不要切了
  @Override
  protected boolean isInfrastructureClass(Class<?> beanClass) {
    return (super.isInfrastructureClass(beanClass) ||
        (this.aspectJAdvisorFactory != null && this.aspectJAdvisorFactory.isAspect(beanClass)));
  }
  // 拿传入的正则模版进行匹配(没传就返回true,所有的Advisor都会生效)
  protected boolean isEligibleAspectBean(String beanName) {
    if (this.includePatterns == null) {
      return true;
    }
    else {
      for (Pattern pattern : this.includePatterns) {
        if (pattern.matcher(beanName).matches()) {
          return true;
        }
      }
      return false;
    }
  }
  ...
}


AspectJAwareAdvisorAutoProxyCreator它用于xml配置版的AspectJ切面自动代理创建(<aop:config/>)

AnnotationAwareAspectJAutoProxyCreator用于基于注解的自动代理创建(<aop:aspectj-autoproxy/> 或 @EnableAspectJAutoProxy)


BeanFactoryAdvisorRetrievalHelper:从Bean工厂检索出Advisor们


这个类很重要,是真正去容器中找出所有的Advisor的类

// @since 2.0.2
public class BeanFactoryAdvisorRetrievalHelper {
  private final ConfigurableListableBeanFactory beanFactory;
  // 本地会做一个简单的字段缓存
  @Nullable
  private String[] cachedAdvisorBeanNames;
  ...
  // 这里显然就是核心方法了
  public List<Advisor> findAdvisorBeans() {
    String[] advisorNames = null;
    synchronized (this) {
      advisorNames = this.cachedAdvisorBeanNames;
      if (advisorNames == null) {
        // 这里不会实例化FactoryBeans
        // 我们需要保留所有常规bean未初始化以允许自动代理创建者应用于它们
        // 注意此处:连祖先容器里面的Bean都会拿出来  (这个方法平时我们也可以使用)
        advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
            this.beanFactory, Advisor.class, true, false);
        this.cachedAdvisorBeanNames = advisorNames;
      }
    }
    // 如果容器里面没有任何的advisor 那就拉倒吧
    if (advisorNames.length == 0) {
      return new LinkedList<>();
    }
    List<Advisor> advisors = new LinkedList<>();
    for (String name : advisorNames) {
      // isEligibleBean:表示这个bean是否是合格的,默认是true
      // 但上面书说了InfrastructureAdvisorAutoProxyCreator和DefaultAdvisorAutoProxyCreator都做了对应的复写
      if (isEligibleBean(name)) {
        // 如果当前Bean正在创建中  那好  就啥也不做吧
        if (this.beanFactory.isCurrentlyInCreation(name)) {
          if (logger.isDebugEnabled()) {
            logger.debug("Skipping currently created advisor '" + name + "'");
          }
        }
        // 否则就把这个Advisor加入到List里面,是个合法的
        else {
          try {
            advisors.add(this.beanFactory.getBean(name, Advisor.class));
          }
          catch (BeanCreationException ex) {
            ... 
            continue;
          }
        }
      }
    }
    return advisors;
  }
  protected boolean isEligibleBean(String beanName) {
    return true;
  }
}


综上,整个Spring AOP中的自动代理创建器就全部介绍完了,相信收货不小吧~~~

不同的实现类都有自己不同的使用场景。但是在注解驱动大行其道的今天,显然AnnotationAwareAspectJAutoProxyCreator这个自动代理创建器是最流行、也是功能最强大、也是最实用的,所以是我们最应该掌握的~~~


总结


总的来说:Spring的知识是个体系,很多都是环环相扣的。学知识和建楼一样,需要从根基开始,否则永远只能是半桶水,容易洒出来


最后,只给使用的时候两个不成熟的小建议吧:


1.SpringAOP应尽量避免自己创建AutoProxyCreator

2.避免使用低级别的AOP API


比如如下情况(我们自己注册一个创建器):


<bean class="org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator">  
    <property name="proxyTargetClass" value="true"/>  
</bean>  
<tx:annotation-driven transaction-manager="transactionManager"/>   

最终我却发现走的依旧是JDK动态代理,不是CGLIB。但是如果我这样:


<aop:aspectj-autoproxy proxy-target-class="true"/>  
<tx:annotation-driven transaction-manager="transactionManager"/>  


就一切正常,走的CGLIB了。至于什么原因,一语道不明,建议还是多看我博文掌握来龙去脉吧(哈哈~~~),读者可以自己思考咯~


相关文章
|
14天前
|
Java Spring
【Spring】方法注解@Bean,配置类扫描路径
@Bean方法注解,如何在同一个类下面定义多个Bean对象,配置扫描路径
140 73
|
2天前
|
存储 安全 Java
Spring Boot 3 集成Spring AOP实现系统日志记录
本文介绍了如何在Spring Boot 3中集成Spring AOP实现系统日志记录功能。通过定义`SysLog`注解和配置相应的AOP切面,可以在方法执行前后自动记录日志信息,包括操作的开始时间、结束时间、请求参数、返回结果、异常信息等,并将这些信息保存到数据库中。此外,还使用了`ThreadLocal`变量来存储每个线程独立的日志数据,确保线程安全。文中还展示了项目实战中的部分代码片段,以及基于Spring Boot 3 + Vue 3构建的快速开发框架的简介与内置功能列表。此框架结合了当前主流技术栈,提供了用户管理、权限控制、接口文档自动生成等多项实用特性。
24 8
|
14天前
|
Java Spring
【Spring配置相关】启动类为Current File,如何更改
问题场景:当我们切换类的界面的时候,重新启动的按钮是灰色的,不能使用,并且只有一个Current File 项目,下面介绍两种方法来解决这个问题。
|
2月前
|
监控 安全 Java
什么是AOP?如何与Spring Boot一起使用?
什么是AOP?如何与Spring Boot一起使用?
76 5
|
2月前
|
Java 开发者 Spring
Spring AOP 底层原理技术分享
Spring AOP(面向切面编程)是Spring框架中一个强大的功能,它允许开发者在不修改业务逻辑代码的情况下,增加额外的功能,如日志记录、事务管理等。本文将深入探讨Spring AOP的底层原理,包括其核心概念、实现方式以及如何与Spring框架协同工作。
|
2月前
|
XML 监控 安全
深入调查研究Spring AOP
【11月更文挑战第15天】
50 5
|
3月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
268 2
|
1天前
|
Java 测试技术 应用服务中间件
Spring Boot 如何测试打包部署
本文介绍了 Spring Boot 项目的开发、调试、打包及投产上线的全流程。主要内容包括: 1. **单元测试**:通过添加 `spring-boot-starter-test` 包,使用 `@RunWith(SpringRunner.class)` 和 `@SpringBootTest` 注解进行测试类开发。 2. **集成测试**:支持热部署,通过添加 `spring-boot-devtools` 实现代码修改后自动重启。 3. **投产上线**:提供两种部署方案,一是打包成 jar 包直接运行,二是打包成 war 包部署到 Tomcat 服务器。
23 10
|
15天前
|
Java 数据库连接 Maven
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
自动装配是现在面试中常考的一道面试题。本文基于最新的 SpringBoot 3.3.3 版本的源码来分析自动装配的原理,并在文未说明了SpringBoot2和SpringBoot3的自动装配源码中区别,以及面试回答的拿分核心话术。
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
|
22天前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
77 14
下一篇
开通oss服务