零、准备知识

1)AOP相关概念:Aspect、Advice、Join point、Pointcut、Weaving、Target等。
2)相关注解:@Aspect、@Pointcut、@Before、@Around、@After、@AfterReturning、@AfterThrowing
 

一、实践目标

1)@Aspect的功能
2)@Pointcut的切面表达式
3)@Before、@Around、@After、@AfterReturning / @AfterThrowing的时序关系
4)AOP概念的重新梳理和使用

二、核心代码

MainController.java包含两个测试函数,分别是doSomething() 和 test()。
 // MainController.java
@RestController
public class MainController {
RequestMapping(value="/doSomething", method = RequestMethod.POST)
@CrossOrigin("*")
public void doSomething() {
System.out.println("This is doSomething");
test();
} @RequestMapping(value="/justTest", method = RequestMethod.POST)
@CrossOrigin("*")
public void test() { System.out.println("This is test");}
}

ExampleAop.java为AOP相关代码,定义了pointcut和多个Advice函数。

 // ExampleAop.java
@Component
@Aspect
@Order(1)
public class ExampleAop { private static final Logger LOGGER = LoggerFactory.getLogger(ExampleAop.class); // 匹配com.example.demo包及其子包下的所有类的所有方法
@Pointcut("execution(* com.example.demo..*.*(..))")
public void executeService() {
} @Before("executeService()")
public void doBeforeAdvice(JoinPoint joinPoint) throws Exception {
LOGGER.info("Before [{}]", joinPoint.getSignature().getName());
} @Around("executeService()")
public void doAroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
LOGGER.info("Around1 [{}]", joinPoint.getSignature().getName());
joinPoint.proceed();
LOGGER.info("Around2 [{}]", joinPoint.getSignature().getName());
} @After("executeService()")
public void doAfterAdvice(JoinPoint joinPoint) throws Exception {
LOGGER.info("After [{}]", joinPoint.getSignature().getName());
} @AfterReturning("executeService()")
public void doAfterReturningAdvice(JoinPoint joinPoint) throws Exception {
LOGGER.info("AfterReturning [{}]", joinPoint.getSignature().getName());
}
}

编译并运行jar包,调用接口/doSomething。

 # 调用接口
curl localhost:8080/doSomething

到服务器观察日志。

 <!-- 后台日志 -->
com.example.demo.aop.ExampleAop : Around1 [doSomething]
com.example.demo.aop.ExampleAop : Before [doSomething]
This is doSomething
This is test
com.example.demo.aop.ExampleAop : Around2 [doSomething]
com.example.demo.aop.ExampleAop : After [doSomething]
com.example.demo.aop.ExampleAop : AfterReturning [doSomething]

三、分析与结论

1)@Aspect的功能
  在连接点的前后添加处理。在本例中,doSomething() 是连接点,而test() 不是。
  是否只有最外层的joinpoint才会被Advice插入?在后面进行简单的探讨和猜测。
 
 
2)@Pointcut的切面表达式
  ref: https://www.jianshu.com/p/fbbdebf200c9  完整表达式
  @Pointcut("execution(...)") 是Pointcut表达式,executeService() 是point签名。表达式中可以包含签名的逻辑运算。
 
  常用表达式:
 execution(public * com.example.demo.ExampleClass.*(..))  // ExampleClass的所有公有方法
execution(* com.example.demo..*.*(..)) // com.example.demo包及其子包下的所有方法
logSender() || logMessage() // 两个签名的表达式的并集
3)@Before、@Around、@After、@AfterReturning / @AfterThrowing的时序关系
  @Around1 -> @Before -> 方法 -> @Around2 -> @After -> @AfterReturning / @AfterThrowing(时序问题后面有额外讨论。)
  另外可以发现,@Around是可以影响程序本身执行的,如果不调用 joinPoint.proceed(); 就不会执行方法。其他几个都无法影响程序执行。
 
 
4)AOP概念的重新梳理和使用
  Aspect(切面):使用了@Aspect注解,如ExampleAop类。
  Advice(增强):在指定位置进行的增强操作,如方法运行时间统计、用户登录、日志记录等。由@Before、@After等注解标注,如doBeforeAdvice() 方法。
  Weaving(织入):AOP就是一种把Advice织入(即嵌入、插入)到Aspect中指定位置执行的机制。
  Join point(连接点):Advice执行的位置,也是Advice的参数,是一个具体的方法。如日志中看到的doSomething() 函数。
  Pointcut(切点):以表达式的形式表示一组join point,用于由@Pointcut注解定义Advice的作用位置。如@Pointcut("execution(* com.example.demo..*.*(..))") 代表com.example.demo包及其子包下的所有类的所有方法。
  Target(对象):被增强的对象,即包含主业务逻辑的类的对象,如ExampleAop类的实例。

四、疑问与讨论

1. 本文说执行顺序为@Around1 -> @Before -> 方法 -> @Around2 -> @After,但有的文章中说是@Before -> @Around1 -> 方法 -> @Around2 -> @After,也有说@Around1 -> @Before -> 方法 -> @After -> @Around2,哪个对?
 
  反正代码跑起来是这个顺序,那就是这个顺序喽。每个Advice都加上sleep拉开时间也没有变化。不知道是否受版本或代码自身影响。
  总之可以得到一个结论:@Before / @After 最好不要和@Around混用,执行顺序不好确定。
  时序至少总是满足:@Around1 / @Before -> 方法 -> @Around2 / @After -> @AfterReturning / @AfterThrowing
  另外找到一篇支持本文执行顺序的文章:https://blog.csdn.net/qq_32331073/article/details/80596084
 
 
2. 为何doSomething() 和 test() 都是@Pointcut中选中的作用节点,但只有doSomething() 插入了Advice,而test() 没有呢?
 
        一个猜测:从字面意思理解,@Pointcut对所有代码以表达式为规则剪一刀,一侧是所有的joinpoint,另一侧是普通代码。在joinpoint与另一侧代码间插入一层Advice的代理,另一侧的代码如果要调用joinpoint,则必须经Advice进行增强操作。而不同的joinpoint在同一侧,因此未插入Advice。
        有时间再读源码了解其中的机制。

(一个猜测)

五、Future Work

1. AOP中还有Advisor等概念,待学习。
2. 切面表达式(@Pointcut里的表达式)规则丰富,待学习。
3. Advice的插入时机,待读源码学习。

Spring入门之AOP实践:@Aspect + @Pointcut + @Before / @Around / @After的更多相关文章

  1. Spring入门4.AOP配置深入

    Spring入门4.AOP配置深入 代码下载 链接: http://pan.baidu.com/s/11mYEO 密码: x7wa 前言: 之前学习AOP中的一些概念,包括连接点.切入点(pointc ...

  2. Spring入门3.AOP编程

    Spring入门3.AOP编程 代码下载: 链接: http://pan.baidu.com/s/11mYEO 密码: x7wa 前言: 前面学习的知识是Spring在Java项目中的IoC或DJ,这 ...

  3. Spring基础系列--AOP实践

    原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9615720.html 本文目的是简单讲解下Spring AOP的使用. 推荐使用IDEA ...

  4. Spring入门之AOP篇

    听了几节IT黑马营的SPRING课程,照着例程写了一个SPRING 中AOP的例子:  一.准备工作 下载复制或配置JAR包.图方便,我将下载的SPRING包都加上去了.另外还需要aspectj的两个 ...

  5. Spring入门篇——AOP基本概念

    1.什么是AOP及实现方式 什么是AOP AOP:Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术 主要 ...

  6. spring 注解 之 AOP基于@Aspect的AOP配置

    Spring AOP面向切面编程,可以用来配置事务.做日志.权限验证.在用户请求时做一些处理等等.用@Aspect做一个切面,就可以直接实现. 1.首先定义一个切面类,加上@Component  @A ...

  7. Spring入门介绍-AOP(三)

    AOP的概念 AOP是面向切面编程的缩写,它是一种编程的新思想.对我们经常提起的oop(面对对象编程)有一定的联系. AOP和OOP的关系 AOP可以说是oop的某一方便的补充,oop侧重于对静态的属 ...

  8. Spring课程 Spring入门篇 5-3 配置切入点 pointcut

    1 解析 1.1 xml常见的配置切入点写法 2 代码演练 2.1 xml配置切入点   1 解析 1.1 xml常见的配置切入点写法 2 代码演练 2.1 xml配置切入点 xml配置: <? ...

  9. 《Java Spring框架》Spring切面(AOP)配置详解

    1.  Spring 基本概念 AOP(Aspect Oriented Programming)称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2 ...

随机推荐

  1. MIT HAKMEM算法-BitCount算法

    MIT HAKMEM算法 1.问题来源 牛客刷题 问题描述: #include <iostream> using namespace std; unsigned int fib(int n ...

  2. 2018中国大学生程序设计竞赛 - 网络选拔赛 hdu Tree and Permutation 找规律+求任意两点的最短路

    Tree and Permutation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Oth ...

  3. CodeForces 1082 D Maximum Diameter Graph

    题目传送门 题意:现在有n个点,每个点的度数最大为di,现在要求你构成一棵树,求直径最长. 题解:把所有度数为2的点先扣出来,这些就是这颗树的主干,也就是最长的距离. 然后我们把度数为2的点连起来,之 ...

  4. 创建最简单的exe形式COM组件并在MFC程序调用

    来新公司学习接手新项目,拿到代码打开解决方案看到里面竟然有40几个工程,有点吃惊.具体看代码也有很多之前没见过的写法,上了几天火. 有件事就没太搞明白,按照文档的说法上层很多软件都要调用IO服务器,但 ...

  5. 【Linux】一些常用命令(待整理)

    一.关机重启命令 二.查询ip 三.查询杀死进程 四.CentOS7 关闭防火墙 五.vim常用 5.1 搜索 5.2 设置行号 剪切 替换 一.关机重启命令 shutdown -h 10 #计算机将 ...

  6. CenTOS7使用ACL控制目录权限,只给某个用户访问特定目录

    前言 Linux 基本的权限控制仅可以对所属用户.所属组.其他用户进行的权限控制,而不能精确地控制每个用户的权限.ACL 规则就是用来解决这个问题的. 使用 ACL 规则,我们可以针对单一账户设置文件 ...

  7. git拉取分支

    拉取仓库代码很简单,直接建立连接在pull下来就可以,如果想要拉取仓库中的某一个分支的话,则可能比较麻烦一点,下面简单介绍了一种拉取仓库分支的方法 1.先新建一个项目文件夹 2.git初始化git i ...

  8. Springboot源码分析之TypeFilter魔力

    摘要: 在平常的开发中,不知道大家有没有想过这样一个问题,为什么我们自定义注解的时候要使用spring的原生注解(这里指的是类似@Component,@Service........),要么就是 随便 ...

  9. flume learning---Flume 集群搭建

    在flume搭建集群模式时,首先需要进入conf目录, 1.cp flume-env.sh.template flume-env.sh 2.cp flume-conf.properties.templ ...

  10. linux非root用户下安装软件,搭建生产环境

    之前的用实验室的服务器,因为某些原因,使用的用户没有root权限.linux的非root用户很多软件无法安装,非常的不方便.我的方法是使用brew来代替系统的包管理工具.brew是最先用在mac上的包 ...