您当前的位置:首页 > 电脑百科 > 程序开发 > 架构

你了解Spring AOP的这个技能点吗?有什么应用场景?

时间:2023-12-08 12:22:44  来源:  作者:Spring全家桶实战案例源码

环境:Spring5.3.23

1. 介绍

今天看Spring文档看到这么一个知识点《Control Flow Pointcuts》都不好翻译

官方原文:

Spring control flow pointcuts are conceptually similar to AspectJ cflow pointcuts, although less powerful. (There is currently no way to specify that a pointcut runs below a join point matched by another pointcut.) A control flow pointcut matches the current call stack. For example, it might fire if the join point was invoked by a method in the com.mycompany.web package or by the SomeCaller class. Control flow pointcuts are specified by using the org.springframework.aop.support.ControlFlowPointcut class.

大意:Spring控制流切入点在概念上类似于aspectj cflow切入点,尽管功能不那么强大。(目前还没有办法指定一个切入点在与另一个切入点匹配的连接点下面运行。)控制流切入点与当前调用堆栈匹配。例如,如果连接点由com.mycompany.web包中的方法或someecaller类调用,则可能会触发该连接点。控制流切入点是通过使用org.springframework.aop.support.ControlFlowPointcut类指定的。

其实看完这个,可能你还是不懂什么意思,接下来我们来跑一个实例,就能明白撒意思了。

2. Control Flow实例

准备几个方法嵌套调用的类

static class PersonDAO {
  public void save(String name) {
    System.out.println("PersonDAO save method invoke...") ;
  }
}
static class PersonService {
  private PersonDAO dao ;
  public PersonService(PersonDAO dao) {
    this.dao = dao ;
  }
  public void save(String name) {
    System.out.println("PersonService save method inovke...") ;
    this.dao.save(name) ;
  }
}


static class PersonManager {
  private PersonService ps ;
  public void setPs(PersonService ps) {
    this.ps = ps ;
  }
  public void index(String name) {
    System.out.println("PersonManager index method invoke...") ;
    this.ps.save(name) ;
  }
}

上面的类及方法调用非常简单:PersonManager ---> PersonService ---> PersonDAO。接下来是通过编程的方式创建PersonService代理对象。

// 实例化上面的类
PersonDAO dao = new PersonDAO() ;
PersonService target = new PersonService(dao) ;


PersonManager pm = new PersonManager() ;


Class<?> clazz = PersonManager.class ;
String methodName = "index" ;
// 定义切入点
ControlFlowPointcut pointcut = new ControlFlowPointcut(clazz, methodName) ;
// 定义通知
MethodInterceptor logInterceptor = invocation -> {
  System.out.println("before log...") ;
  Object ret = invocation.proceed() ;
  System.out.println("after log...") ;
  return ret ;
} ;
// 定义切面


DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, logInterceptor) ;
// 通过ProxyFactory创建代理对象,创建的是PersonService对象的代理
ProxyFactory factory = new ProxyFactory(target) ;
factory.addAdvisor(advisor) ;
// 基于CGLIB生成代理
factory.setProxyTargetClass(true) ;
PersonService ps = (PersonService) factory.getProxy() ;


pm.setPs(ps) ;


pm.index("张三") ;

控制台输出

PersonManager index method invoke...
before log...
PersonService save method inovke...
PersonDAO save method invoke...
after log...

从输出的结果发现,在PersonService#save方法之前之前和之后分别打印了日志信息。原理是什么呢?这里我们需要先看ControlFlowPointcut 切入点是如何工作的。

ControlFlowPointcut核心方法

这里只列出了几个重要的方法,在spring中只支持方法级别的拦截。

public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher, Serializable {
  private final Class<?> clazz;
  @Nullable
  private final String methodName;
  // 对应类级别的匹配全部返回true,就是都匹配
  @Override
  public boolean matches(Class<?> clazz) {
    return true;
  }
  // 方法匹配,直接true
  @Override
  public boolean matches(Method method, Class<?> targetClass) {
    return true;
  }
  // 这里是关键,只有isRuntime返回了true才有可能调用下面3个参数的matches方法
  @Override
  public boolean isRuntime() {
    return true;
  }
  // 该方法的调用需要上面2个参数的matches方法返回true且isRuntime方法也返回true才会调用这里
  @Override
  public boolean matches(Method method, Class<?> targetClass, Object... args) {
    // 遍历当前线程的执行栈情况(也就是当前方法的调用栈情况)
    for (StackTraceElement element : new Throwable().getStackTrace()) {
      // 这里就开始判断当前执行的类是否与给定的类相同 && 当前设置的methodName为空或者当前栈执行的方法名与给定的方法名相同
      if (element.getClassName().equals(this.clazz.getName()) &&
          (this.methodName == null || element.getMethodName().equals(this.methodName))) {
        // 最终这里只有返回了true,我们上面的通知MethodInterceptor才会被执行
        return true;
      }
    }
    return false;
  }
}

有了上面源码的分析后,我们再来看看上面的示例代码:

// 指明要匹配的类
Class<?> clazz = PersonManager.class ;
// 指明要匹配的方法名
String methodName = "index" ;
/** 
 * 将传入到切入点中;而在该切入点的matches方法中进行了判断,
 * 整个执行的线程栈中的所有类及方法是否与这里给定的相同,
 * 只有相同了拦截器才能执行
 */
ControlFlowPointcut pointcut = new ControlFlowPointcut(clazz, methodName) ;

分析到这你应该知道这个Control Flow有撒用了吧,总结:

Control Flow就是用来判断当前执行的线程栈中(所有方法的调用)是否与你给定的类及方法匹配,只有匹配了才能执行我们的增强(通知)代码。

简单说:我PersonService想监控PersonManager中的index方法是否调用了我。

官方有这段说明:

Dynamic pointcuts are costlier to evaluate than static pointcuts. They take into account method arguments as well as static information. This means that they must be evaluated with every method invocation and that the result cannot be cached, as arguments will vary.

The mAIn example is the control flow pointcut.

大意:与静态快捷方式相比,动态快捷方式的评估成本更高。它们会考虑方法参数和静态信息。这意味着每次调用方法时都必须对其进行评估,而且由于参数会发生变化,因此无法缓存评估结果。控制流快捷方式就是一个主要的例子。

3. Control Flow性能

同样来自官方说明:

Control flow pointcuts are significantly more expensive to evaluate at runtime than even other dynamic pointcuts. In JAVA 1.4, the cost is about five times that of other dynamic pointcuts.

大意:与其他动态切入点相比,控制流切入点在运行时评估的成本要高得多。在Java1.4中,成本大约是其他动态切入点的五倍。



Tags:Spring   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
Spring Security:保障应用安全的利器
SpringSecurity作为一个功能强大的安全框架,为Java应用程序提供了全面的安全保障,包括认证、授权、防护和集成等方面。本文将介绍SpringSecurity在这些方面的特性和优势,以及它...【详细内容】
2024-02-27  Search: Spring  点击:(52)  评论:(0)  加入收藏
Spring Security权限控制框架使用指南
在常用的后台管理系统中,通常都会有访问权限控制的需求,用于限制不同人员对于接口的访问能力,如果用户不具备指定的权限,则不能访问某些接口。本文将用 waynboot-mall 项目举例...【详细内容】
2024-02-19  Search: Spring  点击:(39)  评论:(0)  加入收藏
详解基于SpringBoot的WebSocket应用开发
在现代Web应用中,实时交互和数据推送的需求日益增长。WebSocket协议作为一种全双工通信协议,允许服务端与客户端之间建立持久性的连接,实现实时、双向的数据传输,极大地提升了用...【详细内容】
2024-01-30  Search: Spring  点击:(8)  评论:(0)  加入收藏
Spring实现Kafka重试Topic,真的太香了
概述Kafka的强大功能之一是每个分区都有一个Consumer的偏移值。该偏移值是消费者将读取的下一条消息的值。可以自动或手动增加该值。如果我们由于错误而无法处理消息并想重...【详细内容】
2024-01-26  Search: Spring  点击:(84)  评论:(0)  加入收藏
SpringBoot如何实现缓存预热?
缓存预热是指在 Spring Boot 项目启动时,预先将数据加载到缓存系统(如 Redis)中的一种机制。那么问题来了,在 Spring Boot 项目启动之后,在什么时候?在哪里可以将数据加载到缓存系...【详细内容】
2024-01-19  Search: Spring  点击:(86)  评论:(0)  加入收藏
Spring Boot2.0深度实践 核心原理拆解+源码分析
Spring Boot2.0深度实践:核心原理拆解与源码分析一、引言Spring Boot是一个基于Java的轻量级框架,它简化了Spring应用程序的创建过程,使得开发者能够快速搭建一个可运行的应用...【详细内容】
2024-01-15  Search: Spring  点击:(93)  评论:(0)  加入收藏
SpringBoot3+Vue3 开发高并发秒杀抢购系统
开发高并发秒杀抢购系统:使用SpringBoot3+Vue3的实践之旅随着互联网技术的发展,电商行业对秒杀抢购系统的需求越来越高。为了满足这种高并发、高流量的场景,我们决定使用Spring...【详细内容】
2024-01-14  Search: Spring  点击:(90)  评论:(0)  加入收藏
Spring Boot 3.0是什么?
Spring Boot 3.0是一款基于Java的开源框架,用于简化Spring应用程序的构建和开发过程。与之前的版本相比,Spring Boot 3.0在多个方面进行了改进和增强,使其更加易用、高效和灵活...【详细内容】
2024-01-11  Search: Spring  点击:(130)  评论:(0)  加入收藏
GraalVM与Spring Boot 3.0:加速应用性能的完美融合
在2023年,SpringBoot3.0的发布标志着Spring框架对GraalVM的全面支持,这一支持是对Spring技术栈的重要补充。GraalVM是一个高性能的多语言虚拟机,它提供了Ahead-of-Time(AOT)编...【详细内容】
2024-01-11  Search: Spring  点击:(124)  评论:(0)  加入收藏
Spring Boot虚拟线程的性能还不如Webflux?
早上看到一篇关于Spring Boot虚拟线程和Webflux性能对比的文章,觉得还不错。内容较长,抓重点给大家介绍一下这篇文章的核心内容,方便大家快速阅读。测试场景作者采用了一个尽可...【详细内容】
2024-01-10  Search: Spring  点击:(115)  评论:(0)  加入收藏
▌简易百科推荐
对于微服务架构监控应该遵守的原则
随着软件交付方式的变革,微服务架构的兴起使得软件开发变得更加快速和灵活。在这种情况下,监控系统成为了微服务控制系统的核心组成部分。随着软件的复杂性不断增加,了解系统的...【详细内容】
2024-04-03  步步运维步步坑    Tags:架构   点击:(4)  评论:(0)  加入收藏
大模型应用的 10 种架构模式
作者 | 曹洪伟在塑造新领域的过程中,我们往往依赖于一些经过实践验证的策略、方法和模式。这种观念对于软件工程领域的专业人士来说,已经司空见惯,设计模式已成为程序员们的重...【详细内容】
2024-03-27    InfoQ  Tags:架构模式   点击:(13)  评论:(0)  加入收藏
哈啰云原生架构落地实践
一、弹性伸缩技术实践1.全网容器化后一线研发的使用问题全网容器化后一线研发会面临一系列使用问题,包括时机、容量、效率和成本问题,弹性伸缩是云原生容器化后的必然技术选择...【详细内容】
2024-03-27  哈啰技术  微信公众号  Tags:架构   点击:(10)  评论:(0)  加入收藏
DDD 与 CQRS 才是黄金组合
在日常工作中,你是否也遇到过下面几种情况: 使用一个已有接口进行业务开发,上线后出现严重的性能问题,被老板当众质疑:“你为什么不使用缓存接口,这个接口全部走数据库,这怎么能扛...【详细内容】
2024-03-27  dbaplus社群    Tags:DDD   点击:(11)  评论:(0)  加入收藏
高并发架构设计(三大利器:缓存、限流和降级)
软件系统有三个追求:高性能、高并发、高可用,俗称三高。本篇讨论高并发,从高并发是什么到高并发应对的策略、缓存、限流、降级等。引言1.高并发背景互联网行业迅速发展,用户量剧...【详细内容】
2024-03-13    阿里云开发者  Tags:高并发   点击:(5)  评论:(0)  加入收藏
如何判断架构设计的优劣?
架构设计的基本准则是非常重要的,它们指导着我们如何构建可靠、可维护、可测试的系统。下面是这些准则的转换表达方式:简单即美(KISS):KISS原则的核心思想是保持简单。在设计系统...【详细内容】
2024-02-20  二进制跳动  微信公众号  Tags:架构设计   点击:(36)  评论:(0)  加入收藏
详解基于SpringBoot的WebSocket应用开发
在现代Web应用中,实时交互和数据推送的需求日益增长。WebSocket协议作为一种全双工通信协议,允许服务端与客户端之间建立持久性的连接,实现实时、双向的数据传输,极大地提升了用...【详细内容】
2024-01-30  ijunfu  今日头条  Tags:SpringBoot   点击:(8)  评论:(0)  加入收藏
PHP+Go 开发仿简书,实战高并发高可用微服务架构
来百度APP畅享高清图片//下栽のke:chaoxingit.com/2105/PHP和Go语言结合,可以开发出高效且稳定的仿简书应用。在实现高并发和高可用微服务架构时,我们可以采用一些关键技术。首...【详细内容】
2024-01-14  547蓝色星球    Tags:架构   点击:(114)  评论:(0)  加入收藏
GraalVM与Spring Boot 3.0:加速应用性能的完美融合
在2023年,SpringBoot3.0的发布标志着Spring框架对GraalVM的全面支持,这一支持是对Spring技术栈的重要补充。GraalVM是一个高性能的多语言虚拟机,它提供了Ahead-of-Time(AOT)编...【详细内容】
2024-01-11    王建立  Tags:Spring Boot   点击:(124)  评论:(0)  加入收藏
Spring Boot虚拟线程的性能还不如Webflux?
早上看到一篇关于Spring Boot虚拟线程和Webflux性能对比的文章,觉得还不错。内容较长,抓重点给大家介绍一下这篇文章的核心内容,方便大家快速阅读。测试场景作者采用了一个尽可...【详细内容】
2024-01-10  互联网架构小马哥    Tags:Spring Boot   点击:(115)  评论:(0)  加入收藏
站内最新
站内热门
站内头条