Spring入门之AOP实践:@Aspect + @Pointcut + @Before / @Around / @After

零、准备知识

1)AOP相关概念:Aspect、Advice、Join point、Pointcut、Weaving、Target等。

  ref: https://www.cnblogs.com/zhangzongle/p/5944906.html  有代码示例

2)相关注解:@Aspect、@Pointcut、@Before、@Around、@After、@AfterReturning、@AfterThrowing

一、实践目标

1)@Aspect的功能

2)@Pointcut的切面表达式

3)@Before、@Around、@After、@AfterReturning / @AfterThrowing的时序关系

4)AOP概念的重新梳理和使用

二、核心代码

MainController.java包含两个测试函数,分别是doSomething() 和 test()。

 1 // MainController.java
 2 @RestController
 3 public class MainController {
 4     RequestMapping(value="/doSomething", method = RequestMethod.POST)
 5     @CrossOrigin("*")
 6     public void doSomething() {
 7         System.out.println("This is doSomething");
 8         test();
 9     }
10
11     @RequestMapping(value="/justTest", method = RequestMethod.POST)
12     @CrossOrigin("*")
13     public void test() { System.out.println("This is test");}
14 }

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

 1 // ExampleAop.java
 2 @Component
 3 @Aspect
 4 @Order(1)
 5 public class ExampleAop {
 6
 7     private static final Logger LOGGER = LoggerFactory.getLogger(ExampleAop.class);
 8
 9     // 匹配com.example.demo包及其子包下的所有类的所有方法
10     @Pointcut("execution(* com.example.demo..*.*(..))")
11     public void executeService() {
12     }
13
14     @Before("executeService()")
15     public void doBeforeAdvice(JoinPoint joinPoint) throws Exception {
16         LOGGER.info("Before [{}]", joinPoint.getSignature().getName());
17     }
18
19     @Around("executeService()")
20     public void doAroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
21         LOGGER.info("Around1 [{}]", joinPoint.getSignature().getName());
22         joinPoint.proceed();
23         LOGGER.info("Around2 [{}]", joinPoint.getSignature().getName());
24     }
25
26     @After("executeService()")
27     public void doAfterAdvice(JoinPoint joinPoint) throws Exception {
28         LOGGER.info("After [{}]", joinPoint.getSignature().getName());
29     }
30
31     @AfterReturning("executeService()")
32     public void doAfterReturningAdvice(JoinPoint joinPoint) throws Exception {
33         LOGGER.info("AfterReturning [{}]", joinPoint.getSignature().getName());
34     }
35 }

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

1 # 调用接口
2 curl localhost:8080/doSomething

到服务器观察日志。

1 <!-- 后台日志 -->
2 com.example.demo.aop.ExampleAop          : Around1 [doSomething]
3 com.example.demo.aop.ExampleAop          : Before [doSomething]
4 This is doSomething
5 This is test
6 com.example.demo.aop.ExampleAop          : Around2 [doSomething]
7 com.example.demo.aop.ExampleAop          : After [doSomething]
8 com.example.demo.aop.ExampleAop          : AfterReturning [doSomething]

三、分析与结论

1)@Aspect的功能

  在连接点的前后添加处理。在本例中,doSomething() 是连接点,而test() 不是。

  是否只有最外层的joinpoint才会被Advice插入?在后面进行简单的探讨和猜测。

2)@Pointcut的切面表达式

  ref: https://www.cnblogs.com/liaojie970/p/7883687.html  常用表达式

  ref: https://www.jianshu.com/p/fbbdebf200c9  完整表达式

  @Pointcut("execution(...)") 是Pointcut表达式,executeService() 是point签名。表达式中可以包含签名的逻辑运算。

  常用表达式:

1 execution(public * com.example.demo.ExampleClass.*(..))  // ExampleClass的所有公有方法
2 execution(* com.example.demo..*.*(..)) // com.example.demo包及其子包下的所有方法
3 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

2. 为何doSomething() 和 test() 都是@Pointcut中选中的作用节点,但只有doSomething() 插入了Advice,而test() 没有呢?

一个猜测:从字面意思理解,@Pointcut对所有代码以表达式为规则剪一刀,一侧是所有的joinpoint,另一侧是普通代码。在joinpoint与另一侧代码间插入一层Advice的代理,另一侧的代码如果要调用joinpoint,则必须经Advice进行增强操作。而不同的joinpoint在同一侧,因此未插入Advice。

有时间再读源码了解其中的机制。

(一个猜测)

五、Future Work

1. AOP中还有Advisor等概念,待学习。

2. 切面表达式(@Pointcut里的表达式)规则丰富,待学习。

3. Advice的插入时机,待读源码学习。

原文地址:https://www.cnblogs.com/desertfish/p/11421260.html

时间: 2024-10-09 08:54:25

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

Spring入门篇——AOP基本概念

1.什么是AOP及实现方式 什么是AOP AOP:Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术 主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等 AOP实现方式 预编译 -ApectJ 运行期动态代理(JDK动态代理.CGLib动态代理) -SpringAOP.JbossAOP 2.AOP基本概念 连接点:比如一个类中某个方法执行的开始 通知:在某个方法执行的时候,额外执行的切面

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

Spring AOP面向切面编程,可以用来配置事务.做日志.权限验证.在用户请求时做一些处理等等.用@Aspect做一个切面,就可以直接实现. 1.首先定义一个切面类,加上@Component  @Aspect这两个注解 @Component@Aspectpublic class LogAspect { private static final Logger logger = LoggerFactory.getLogger(LogAspect.class); private static fin

Spring入门介绍-AOP(三)

AOP的概念 AOP是面向切面编程的缩写,它是一种编程的新思想.对我们经常提起的oop(面对对象编程)有一定的联系. AOP和OOP的关系 AOP可以说是oop的某一方便的补充,oop侧重于对静态的属性和方法组合为对象,使得逻辑更加清晰,而aop是是从动态角度考虑,处理过程中某个步骤或者阶段,是从动态角度考虑的. AOP的功能 主要处理事务,日志,安全,异常统计等功能. AOP的价值 AOP专门用于处理分布于各个各个模块中的交叉关注点的问题,在J2ee应用中.通常用AOP来处理一些具有横切性质的

Spring入门导读——IoC和AOP

和MyBatis系列不同的是,在正式开始Spring入门时,我们先来了解两个关于Spring核心的概念,IoC(Inverse of Control)控制反转和AOP()面向切面编程. 1.IoC(Inversion of Control)控制反转 什么是控制反转呢?可以这么通俗的来解释,我们通常写代码当一个类会关联另一个类是会直接在这个类里new,例如: 1 package day_30_spring; 2 3 /** 4 * @author 余林丰 5 * 6 * 2016年10月30日 7

Spring @AspectJ 实现AOP 入门例子(转)

AOP的作用这里就不再作说明了,下面开始讲解一个很简单的入门级例子. 引用一个猴子偷桃,守护者守护果园抓住猴子的小情节. 1.猴子偷桃类(普通类): Java代码   package com.samter.common; /** * 猴子 * @author Administrator * */ public class Monkey { public void stealPeaches(String name){ System.out.println("[猴子]"+name+&quo

Spring入门(二)— IOC注解、Spring测试AOP入门

一.Spring整合Servlet背后的细节 1. 为什么要在web.xml中配置listener <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> 配置listener主要是为了捕获项目发布 | 服务器启动的契机 ,为了解析xml , 创建工厂. 这个listener是spring官方提供

Spring入门IOC和AOP学习笔记

Spring入门IOC和AOP学习笔记 概述 Spring框架的核心有两个: Spring容器作为超级大工厂,负责管理.创建所有的Java对象,这些Java对象被称为Bean. Spring容器管理容器中Bean之间的依赖关系,使用一种叫做"依赖注入"的方式来管理bean之间的依赖关系. Spring有两个核心接口:BeanFactory和ApplicationContext,ApplicationContext是BeanFactory的子接口.它们都可以代表Spring容器,Spri

Spring AOP 的@Aspect

Spring AOP 的@Aspect 转自:http://blog.csdn.net/tanghw/article/details/3862987 从Spring 2.0开始,可以使用基于schema及@AspectJ的方式来实现AOP,本文以一个简单的实例介绍了如何以@AspectJ方式在Spring中实现AOP.由于@Aspect是基于注解的,因此要求支持注解的5.0版本以上的JDK. 环境要求:     1. Web应用     2. 有一个专门提供系统服务的Service层 我们的目标

Spring事务管理—aop:pointcut expression解析

先来看看这个spring的配置文件的配置: <!-- 事务管理器 -->  <bean id="transactionManager"   class="org.springframework.orm.hibernate3.HibernateTransactionManager">   <property name="sessionFactory" ref="sessionFactory" /&g