前面两篇分别介绍了AOP的基本使用姿势和一些高级特性,当时还遗留了一个问题没有说明,即不同的advice,拦截同一个目标方法时,优先级是怎样的,本篇博文将进行详细分析
  
  同一个切面中,不同类型的advice的优先级
  
  同一个切面中,同一种类型的advice优先级
  
  不同切面中,同一类型的advice优先级
  
  不同切面中,不同类型的advice优先级
  
  <!-- more -->
  
  I. 统一切面,不同类型ddvice优先级
  
  在不分析源码的前提下,也只能通过实际的case来看优先级问题了,我们现在设计一下使用实例,通过输出结果来看对应的优先级
  
  1. case设计
  
  首先创建被拦截的bean: com.git.hui.boot.aop.order.InnerDemoBean
  
  @Component
  
  public class InnerDemoBean {
  
  public String print() {
  
  try {
  
  System.out.println("in innerDemoBean start!");
  
  String rans = System.currentTimeMillis() + "|" + UUID.randomUUID();
  
  System.out.println(rans);
  
  return rans;
  
  } finally {
  
  System.out.println("in innerDemoBean over!");
  
  }
  
  }
  
  }
  
  接下来写一个切面,里面定义我们常见的各种advice
  
  对于aop的使用,有疑问的可以参考: 190301-SpringBoot基础篇AOP之基本使用姿势小结
  
  @Component
  
  @Aspect
  
  public class OrderAspect {
  
  @Pointcut("execution(public * com.git.hui.boot.aop.order.*.*())")
  
  public void point() {
  
  }
  
  @Before(value = "point()")
  
  public void doBefore(JoinPoint joinPoint) {
  
  System.out.println("do before!");
  
  }
  
  @After(value = "point()")
  
  public void doAfter(JoinPoint joinPoint) {
  
  System.out.println("do after!");
  
  }
  
  @AfterReturning(value = "point()", returning = "ans")
  
  public void doAfterReturning(JoinPoint joinPoint, String ans) {
  
  System.out.println("do after return: " + ans);
  
  }
  
  @Around("point()")
  
  public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
  
  try {
  
  System.out.println("do in around before");
  
  return joinPoint.proceed();
  
  } finally {
  
  System.out.println("do in around over!");
  
  }
  
  }
  
  }
  
  2. 测试
  
  使用SpringBoot的项目进行测试aop,使用还是比较简单的
  
  @SpringBootApplication
  
  public class Application {
  
  private InnerDemoBean innerDemoBean;
  
  public Application(InnerDemoBean innerDemoBean) {
  
  this.innerDemoBean = innerDemoBean;
  
  this.innerDemoBean();
  
  }
  
  private void innerDemoBean() {
  
  System.out.println("result: " + innerDemoBean.print());
  
  }
  
  public static void main(String[] args) {
  
  SpringApplication.run(Application.class);
  
  }
  
  }
  
  看下上面执行的输出结果
  
  do in around before
  
  do before!
  
  in innerDemoBean start!
  
  1552219604035|e9a31f44-6a31-4485-806a-834361842ce1
  
  in innerDemoBean over!
  
  do in around over!
  
  do after!
  
  do after return: 1552219604035|e9a31f44-6a31-4485-806a-834361842ce1
  
  result: 1552219604035|e9a31f44-6a31-4485-806a-834361842ce1
  
  从输出结果进行反推,我们可以知道统一切面中,advice执行的先后顺序如下
  
  IMAGE
  
  II. 同一切面,同一类型切面
  
  正常来讲,拦截一个方法时,统一类型的切面逻辑都会写在一起,那这个case有什么分析的必要呢?
  
  在我们实际的使用中,同一类型的advice拦截同一个方法的可能性还是很高的,why? 因为多个advice有自己定义的拦截规则,它们之间并不相同,但可能存在交集,比如我们在上面的切面中,再加一个拦截注解的before advice
  
  1. case设计
  
  依然是上面的InnerDemoBean,方法上加一个自定义注解
  
  @AnoDot
  
  public String print() {
  
  try {
  
  System.out.println("in innerDemoBean start!");
  
  String rans = System.currentTimeMillis() + "|" + UUID.randomUUID();
  
  System.out.println(rans);
  
  return rans;
  
  } finally {
  
  System.out.println("in innerDemoBean over!");
  
  }
  
  }
  
  然后加一个拦截注解的advice
  
  @Before("@annotation(AnoDot)")
  
  public void doAnoBefore(JoinPoint joinPoint) {
  
  System.out.println("dp AnoBefore");
  
  }
  
  2. 测试
  
  再次执行前面的case,然后看下输出结果如下
  
  In NetAspect doAround before!
  
  do in around before
  
  dp AnoBefore
  
  do before!
  
  in innerDemoBean start!
  
  1552221765322|d92b6d37-0025-43c0-adcc-c4aa7ba639e0
  
  in innerDemoBean over!
  
  do in around over!
  
  do after!
  
  do after return: 1552221765322|d92b6d37-0025-43c0-adcc-c4aa7ba639e0
  
  In NetAspect doAround over! ans: 1552221765322|d92b6d37-0025-43c0-adcc-c4aa7ba639e0
  
  result: 1552221765322|d92b6d37-0025-43c0-adcc-c4aa7ba639e0
  
  我们主要看下两个before,发现 AnoBefore 在前面; 因此这里的一个猜测,顺序就是根据方法命名的顺序来的,比如我们再加一个 doXBefore,然后我们预估输出结果应该是
  
  do AnoBefore > doBefore > doXBefore
  
  额外添加一个
  
  @Before("@annotation(AnoDot)")
  
  public void doXBefore(JoinPoint joinPoint) {
  
  System.out.println("dp XBefore");
  
  }
  
  接着就是输出结果如下,和我们预期一致
  
  IMAGE
  
  3. Order注解尝试
  
  我们知道有个Order注解可以来定义一些优先级,那么把这个注解放在advice方法上,有效么?实际尝试一下
  
  @Order(1)
  
  @Before(value = "point()")
  
  public void doBefore(JoinPoint joinPoint) {
  
  System.out.println("do before!");
  
  }
  
  @Order(2)
  
  @Before("@annotation(AnoDot)")
  
  public void doAnoBefore(JoinPoint joinPoint) {
  
  System.out.println("dp AnoBefore"www.jrgjze.com/);
  
  }
  
  @Order(3)
  
  @Before("@annotation(AnoDot)")
  
  public void doXBefore(JoinPoint joinPoint) {
  
  System.out.println("dp XBefore");
  
  }
  
  如果注解有效,我们预期输出结果如下
  
  do Before > do AnoBefore > do XBefore
  
  然后再次执行,看下输出结果是否和我们预期一样
  
  IMAGE
  
  4. 小结
  
  同一个切面中,相同的类型的advice,优先级是根据方法命名来的,加@Order注解是没有什么鸟用的,目前也没有搜索到可以调整优先级的方式
  
  III. 不同切面,相同类型的advice
  
  如果说上面这种case不太好理解为啥会出现的话,那么这个可能就容易理解多了;毕竟一个切面完成一件事情,出现相同的advice就比较常见了;
  
  比如spring mvc中,我们通常会实现的几个切面
  
  一个before advice的切面,实现输出请求日志
  
  一个before advice的切面,实现安全校验(这种其实更常见的是放在filter/intercept中)
  
  1. case设计
  
  现在就需要再加一个切面,依然以before advice作为case
  
  @Aspect
  
  @Component
  
  public class AnotherOrderAspect {
  
  @Before("@annotation(AnoDot)")
  
  public void doBefore(www.dfgjpt.com) {
  
  System.out.println("in AnotherOrderAspect before!");
  
  }
  
  }
  
  2. 测试
  
  接下来看测试输出结果如下图
  
  IMAGE
  
  发现了一个有意思的事情了,AnotherOrderAspect切面的输出,完全在OrderAspect切面中所有的advice之前,接着我们再次尝试使用@Order注解来试试,看下会怎样
  
  @Order(0)
  
  @Component
  
  @Aspect
  
  public class OrderAspect {
  
  }
  
  @Aspect
  
  @Order(www.yongshi123.cn)
  
  @Component
  
  public class AnotherOrderAspect {
  
  }
  
  如果顺序有关,我们预期的输出结果应该是
  
  do AnoBefore > do Before > doXBefore > do AnotherOrderAspect before!
  
  实际测试输出如下,和我们预期一致
  
  IMAGE
  
  3. 小结
  
  从上面的测试来看,不同的切面,默认顺序实际上是根据切面的命令来的;
  
  A切面中的advice会优先B切面中同类型的advice
  
  我们可以通过 Order 注解来解决不同切面的优先级问题,依然是值越小,优先级越高
  
  IV. 不同切面,不同advice顺序
  
  其实前面的case已经可以说明这个问题了,现在稍稍丰富一下AnotherOrderAspect,看下结果
  
  1. case设计
  
  @Aspect
  
  @Order(10)
  
  @Component
  
  public class AnotherOrderAspect {
  
  @Before("@annotation(AnoDot)")
  
  public void doBefore(www.xianjingshuiqi.com) {
  
  System.out.println("in AnotherOrderAspect before!");
  
  }
  
  @After("@annotation(AnoDot)www.gen-okamoto.com")
  
  public void doAfter(JoinPoint joinPoint) {
  
  System.out.println("do AnotherOrderAspect after!");
  
  }
  
  @AfterReturning(value = "@annotation(AnoDot)", returning = "ans")
  
  public void doAfterReturning(JoinPoint joinPoint, String ans) {
  
  System.out.println(www.hengtongyoule.com"do AnotherOrderAspect after return: " + ans);
  
  }
  
  @Around("@annotation(AnoDot)")
  
  public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
  
  try {
  
  System.out.println("do AnotherOrderAspect in around before");
  
  return joinPoint.proceed();
  
  } finally {
  
  System.out.println("do AnotherOrderAspect in around over!");
  
  }
  
  }
  
  }
  
  2. 测试
  
  看下执行后的输出结果
  
  IMAGE
  
  假设A切面优先级高于B切面,那么我们执行先后顺序如下
  
  IMAGE
  
  V. 小结
  
  本篇内容有点多,针对前面的测试以及结果分析,给出一个小结,方便直接获取最终的答案
  
  1. 不同advice之间的优先级顺序
  
  around 方法执行前代码 > before > 方法执行 > around方法执行后代码 > after > afterReturning/@AfterThrowing
  
  2. 统一切面中相同advice
  
  统一切面中,同类型的advice的优先级根据方法名决定,暂未找到可以控制优先级的使用方式
  
  3. 不同切面优先级
  
  不同切面优先级,推荐使用 @Order注解来指定,数字越低,优先级越高
  
  4. 不同切面advice执行顺序
  
  优先级高的切面中的advice执行顺序会呈现包围优先级低的advice的情况,更直观的先后顺序,推荐看第四节的顺序图,更加清晰明了
  
  VI. 其他
  
  0. 项目
  
  工程:https://www.meiwanyule.cn/ github.com/liuyueyi/spring-boot-demo
  
  module: https://www.jlzkyy.com github.com/liuyueyi/spring-boot-demo/tree/master/spring-boot/010-aop
  
  1. 一灰灰Blog
  
  一灰灰Blog个人博客 https://www.xycheng178.com blog.hhui.top
  
  一灰灰Blog-Spring专题博客 http://www.mren2yule.com/ spring.hhui.top
  
  一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛
  
  2. 声明
  
  尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

SpringCloud基础篇AOP之拦截优先级详解的更多相关文章

  1. java基础篇---JSP内置对象详解

    在JSP中为了简化用户的开发,提供了九个内置对象,这些内置对象将由容器为用户进行实例化,而用户直接使用即可,而不用像在java中那样,必须通过关键字new进行实例化对象之后才可以使用.   No. 内 ...

  2. Vue.js 源码分析(六) 基础篇 计算属性 computed 属性详解

    模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的.在模板中放入太多的逻辑会让模板过重且难以维护,比如: <div id="example">{{ messag ...

  3. Java基础-DBCP连接池(BasicDataSource类)详解

    Java基础-DBCP连接池(BasicDataSource类)详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 实际开发中“获得连接”或“释放资源”是非常消耗系统资源的两个过程 ...

  4. “全栈2019”Java多线程第十一章:线程优先级详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  5. Java基础13:反射与注解详解

    Java基础13:反射与注解详解 什么是反射? 反射(Reflection)是Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性. Orac ...

  6. Mysql高手系列 - 第18篇:mysql流程控制语句详解(高手进阶)

    Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能. 这是Mysql系列第18篇. 环境:mysql5.7.25,cmd命令中进行演示. 代码中被[]包含的表示可选,|符 ...

  7. 精讲RestTemplate第4篇-POST请求方法使用详解

    本文是精讲RestTemplate第4篇,前篇的blog访问地址如下: 精讲RestTemplate第1篇-在Spring或非Spring环境下如何使用 精讲RestTemplate第2篇-多种底层H ...

  8. GoLang基础数据类型--->字典(map)详解

    GoLang基础数据类型--->字典(map)详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.   可能大家刚刚接触Golang的小伙伴都会跟我一样,这个map是干嘛的,是 ...

  9. GoLang基础数据类型-切片(slice)详解

    GoLang基础数据类型-切片(slice)详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 数组的长度在定义之后无法再次修改:数组是值类型,每次传递都将产生一份副本.显然这种数 ...

随机推荐

  1. kafka学习2:kafka集群安装与配置

    在前一篇:kafka学习1:kafka安装 中,我们安装了单机版的Kafka,而在实际应用中,不可能是单机版的应用,必定是以集群的方式出现.本篇介绍Kafka集群的安装过程: 一.准备工作 1.开通Z ...

  2. 如何构造分层次的 Json 数据

    十年河东,十年河西,莫欺骚年穷...打错个字~_~ 现有如下需求,构造分层次的Json数据,层次结构类似下图: 上图使用EasyUI生成的,静态HTML如下: <html xmlns=" ...

  3. 2016年总结 - Java程序员

    一 . 技术积累 (1)代码规范 1.1.1.通常的模块分布:一般如果你要实现一个web应用,你从后台将数据展示到前端页面,在一个比较大的公司,你少不了跟其他项目有交集(你调用他的接口,他依赖你的接口 ...

  4. Python从菜鸟到高手(5):数字

    1 基础知识   Python语言与其他编程语言一样,也支持四则运算(加.减.乘.除),以及圆括号运算符.在Python语言中,数字分为整数和浮点数.整数就是无小数部分的数,浮点数就是有小数部分的数. ...

  5. UWP简单示例(三):快速开发2D游戏引擎

    准备 IDE:Visual Studio 图形 API:Win2D MSDN 教程:UWP游戏开发 游戏开发涉及哪些技术? 游戏开发是一门复杂的艺术,编码方面你需要考虑图形.输入和网络 以及相对独立的 ...

  6. 关于Win10下IE11只能以管理员身份运行的处理方式

    今天无意间发现IE无法启动,后来研究发现只有用管理员身份运行才能打开,初步分析应该是用户权限的问题,在网上百度了一番,找到了处理的方法,在此分享一下 1.win+R 调出“运行”命令,输入“reged ...

  7. Websocket(一)——原理及基本属性和方法

    初次接触 WebSocket 的人,都会问同样的问题:我们已经有了 HTTP 协议,为什么还需要另一个协议?它能带来什么好处? 答案很简单,因为 HTTP 协议有一个缺陷:通信只能由客户端发起. 举例 ...

  8. PairWork-电梯调度程序结对编程

    结对编程人员:050/184 1 结对编程 1.1 结对编程的优缺点 优点: ● 与单独开发相比,结对能够使人们在压力之下保持更好的状态.结对编程鼓励双方保持代码的高质量,即使在出现了让人不得不飞快地 ...

  9. 关于在VB.NET中调用使用VC++编写的类库dll的一点笔记

    前言 结对作业要求一出来,我就立刻想到了把“计算核心”封装成dll,然后使用vb.net编写UI调用dll的思路.然而在实现过程中却遇到了很多的问题. 我在这个过程中是负责使用vb.net编写UI并调 ...

  10. 07-java学习-方法重载-idea集成开发工具学习-项目-模块-包

    方法重载的概念? 方法重载的好处? 集成开发工具idea的学习 下载 安装 设置 建项目 导入项目 建模块 导入模块 建包 复制粘贴包 建类 复制粘贴类 运行 调试