简单来说讲,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。

AOP几个术语


  1. 切面

切面是通知和切点的结合。通知和切点共同定义了切面的全部内容——它是什么,在何时和何处完成其功能。比如事务管理是一个切面,权限管理也是一个切面。

  1. 通知

通知定义了切面是什么以及何时使用。

Spring切面中定义了5个通知类型:

* 前置通知:在目标方法调用之前执行

* 后置通知:在目标方法调用之后执行

* 返回通知:在目标方法成功执行之后执行

* 异常通知:在目标方法抛出异常之后执行

* 环绕通知:通知包裹了方法,可同时定义前置和后置通知。

  1. 切点

切点定义了在何处工作,也就是在那个方法应用通知。

  1. 连接点

连接点是在应用执行过程中能够插入切面的一个点。这个点可以是调用方法时,抛出异常时,甚至修改一个字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为

  1. 引入

引入让一个切面可以声明被通知的对象实现了任何他们没有真正实现的额外接口,而且为这些对象提供接口的实现。

引入允许我们向现有的类添加新方法或属性。这个新方法和实例变量就可以被引入到现有的类中,从而可以再无需修改这些现有的类的情况下,让它们具有新的行为和状态。

  1. 织入

织入是把切面应用到目标对象并创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中。在目标对象的生命周期里有多个点可以织入。

AOP Demo


下面是一个小Demo

引入Maven依赖

<!--引入SpringBoot的Web模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <!--引入AOP依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

一个简单的Controller

package com.example.demo.aop;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; /**
* @desc: 核心业务模块
* @author: CSH
**/
@RestController
@RequestMapping("/aopController")
public class AopController { @RequestMapping(value = "/Curry")
public void Curry(){
System.out.println("库里上场打球了!!");
} @RequestMapping(value = "/Harden")
public void Harden(){
System.out.println("哈登上场打球了!!");
} @RequestMapping(value = "/Antetokounmpo")
public void Antetokounmpo(){
System.out.println("字母哥上场打球了!!");
} @RequestMapping(value = "/Jokic")
public void Jokic(){
System.out.println("约基奇上场打球了!!");
} @RequestMapping(value = "/Durant/{point}")
public void Durant(@PathVariable("point") int point){
System.out.println("杜兰特上场打球了!!");
}
}

定义切面类

在类上添加@Aspect 和@Component 注解即可将一个类定义为切面类。

@Aspect 注解 使之成为切面类

@Component 注解 把切面类加入到IOC容器中

package com.example.demo.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component; /**
* @desc: 经纪人切面
* @author: CSH
**/
@Aspect
@Component
public class BrokerAspect { /**
* 定义切入点,切入点为com.example.demo.aop.AopController中的所有函数
*通过@Pointcut注解声明频繁使用的切点表达式
*/
@Pointcut("execution(public * com.example.demo.aop.AopController.*(..)))")
public void BrokerAspect(){ } /**
* @description 在连接点执行之前执行的通知
*/
@Before("BrokerAspect()")
public void doBeforeGame(){
System.out.println("经纪人正在处理球星赛前事务!");
} /**
* @description 在连接点执行之后执行的通知(返回通知和异常通知的异常)
*/
@After("BrokerAspect()")
public void doAfterGame(){
System.out.println("经纪人为球星表现疯狂鼓掌!");
} /**
* @description 在连接点执行之后执行的通知(返回通知)
*/
@AfterReturning("BrokerAspect()")
public void doAfterReturningGame(){
System.out.println("返回通知:经纪人为球星表现疯狂鼓掌!");
} /**
* @description 在连接点执行之后执行的通知(异常通知)
*/
@AfterThrowing("BrokerAspect()")
public void doAfterThrowingGame(){
System.out.println("异常通知:球迷要求退票!");
}
}

上面前置通知后置通知等都需要配置到定义的切点上。可以定义好多个切点@Pointcut

调用服务

调用http://localhost:8080/aopController/Harden,输出结果:

切点表达式

参考文章

环绕通知

Spring中使用次数最多的是环绕通知,

/**
* @description 使用环绕通知
*/
@Around("BrokerAspect()")
public void doAroundGame(ProceedingJoinPoint pjp) throws Throwable {
try{
System.out.println("经纪人正在处理球星赛前事务!");
pjp.proceed();
System.out.println("返回通知:经纪人为球星表现疯狂鼓掌!");
}
catch(Throwable e){
System.out.println("异常通知:球迷要求退票!");
}
}

环绕通知接收一个ProceedingJoinPoint参数,可以用他来调用被通知方法,当调用proceed()方法之前,环绕通知可以做任何操作,控制权在环绕通知中,在调用proceed()方法之后,控制权返回被通知方法,被通知方法执行结束之后,控制权返回到环绕通知手中,继续执行后续操作。如果不调用proceed()方法,则被通知方法会被一直阻塞,一直不会执行,多用于权限验证。

当需要传递参数时:

package com.example.demo.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component; /**
* @desc:技术统计
* @author: CSH
**/
@Aspect
@Component
public class GameDataAspect {
/**
* 定义切入点,切入点为com.example.demo.aop.AopController中的所有函数
*通过@Pointcut注解声明频繁使用的切点表达式
*/
@Pointcut("execution(public * com.example.demo.aop.AopController.Durant(int)) && args(point))")
public void GameDataAspect(int point){ } /**
* @description 使用环绕通知
*/
@Around("GameDataAspect(point)")
public void doAroundGameData(ProceedingJoinPoint pjp,int point) throws Throwable {
try{
System.out.println("球星上场前热身!");
pjp.proceed();
System.out.println("球星本场得到" + point + "分" );
}
catch(Throwable e){
System.out.println("异常通知:球迷要求退票!");
}
}
}

参考文章:https://www.cnblogs.com/LemonFive/p/10983875.html

Spring Boot AOP的使用的更多相关文章

  1. Spring Boot AOP解析

    Spring Boot AOP 面向切面编程(AOP)通过提供另一种思考程序结构的方式来补充面向对象编程(OOP). OOP中模块化的关键单元是类,而在AOP中,模块化单元是方面. AOP(Aspec ...

  2. Spring Boot AOP之对请求的参数入参与返回结果进行拦截处理

    Spring Boot AOP之对请求的参数入参与返回结果进行拦截处理   本文链接:https://blog.csdn.net/puhaiyang/article/details/78146620 ...

  3. 玩转spring boot——AOP与表单验证

    AOP在大多数的情况下的应用场景是:日志和验证.至于AOP的理论知识我就不做赘述.而AOP的通知类型有好几种,今天的例子我只选一个有代表意义的“环绕通知”来演示. 一.AOP入门 修改“pom.xml ...

  4. Spring Boot - AOP(面向切面)

    AOP 全称 Aspect Oriented Programming(面向切面),AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分 ...

  5. spring boot aop打印http请求回复日志包含请求体

    一.引入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...

  6. Spring boot AOP 记录请求日志

    如何将所有的通过url的请求参数以及返回结果都输出到日志中? 如果在controller的类中每个方法名都写一个log输出肯定是不明智的选择. 使用spring的AOP功能即可完成. 1. 在pom. ...

  7. redis分布式锁-spring boot aop+自定义注解实现分布式锁

    接这这一篇redis分布式锁-java实现末尾,实现aop+自定义注解 实现分布式锁 1.为什么需要 声明式的分布式锁 编程式分布式锁每次实现都要单独实现,但业务量大功能复杂时,使用编程式分布式锁无疑 ...

  8. Spring Boot AOP 扫盲,实现接口访问的统一日志记录

    AOP 是 Spring 体系中非常重要的两个概念之一(另外一个是 IoC),今天这篇文章就来带大家通过实战的方式,在编程猫 SpringBoot 项目中使用 AOP 技术为 controller 层 ...

  9. Spring Boot AOP

    AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是Spring框架中的一个重要内容,它通 ...

  10. Spring boot Aop 示例

    需要的依赖 <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop -- ...

随机推荐

  1. Python实用笔记 (18)面向对象编程——类和实例

    类和实例 面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各 ...

  2. LeetCode54. 螺旋矩阵

    题意是,输入一个二维数组,从数组左上角开始,沿着顺时针慢慢地"遍历"每一个元素且每一个元素只遍历一次, 在一个新的一维数组中记录遍历的顺序,最终的返回值就是这个数组. 思路:可以考 ...

  3. 117.填充每个节点的下一个右侧节点指针II

    # Definition for a Node.class Node: def __init__(self, val: int = 0, left: 'Node' = None, right: 'No ...

  4. Java项目开启远程调试(tomcat、springboot)

    当我们运行一个项目的时候,一般都是在本地进行debug.但是如果是一个分布式的微服务,这时候我们选择远程debug是我们开发的利器. 环境apache-tomcat-8.5.16 Linux 如何启用 ...

  5. 键盘鼠标(PS2)模拟器驱动及Demo

    详情 KeyboardMouseSimulateDriver 问题描述: 鼠标相对移动存在不正确性,绝对移动没正确性. 基于于Thinkpad E460上的开发及测试. 不支持HID设备.

  6. 运用设计模式告别项目中大量臃肿的if else

    前言 以前写过的一个老项目中,有这样一个业务场景,比喻:一个外卖系统需要接入多家餐馆,在外卖系统中返回每个餐馆的菜单列表 ,每个餐馆的菜单价格都需要不同的算法计算. 代码中使用了大量的if else嵌 ...

  7. JVM源码分析之Object.wait/notify实现

    ​ “365篇原创计划”第十一篇.   今天呢!灯塔君跟大家讲:   JVM源码分析之Object.wait/notify实现       最简单的东西,往往包含了最复杂的实现,因为需要为上层的存在提 ...

  8. 记一道CTF隐写题解答过程

      0x00 前言 由于我是这几天才开始接触隐写这种东西,所以作为新手我想记录一下刚刚所学.这道CTF所需的知识点包括了图片的内容隐藏,mp3隐写,base64解密,当铺解密,可能用到的工具包括bin ...

  9. 【高并发】面试官问我如何使用Nginx实现限流,我如此回答轻松拿到了Offer!

    写在前面 最近,有不少读者说看了我的文章后,学到了很多知识,其实我本人听到后是非常开心的,自己写的东西能够为大家带来帮助,确实是一件值得高兴的事情.最近,也有不少小伙伴,看了我的文章后,顺利拿到了大厂 ...

  10. Python比较操作符、变量赋值、对象拷贝

    Python比较操作符.变量赋值.对象拷贝 目录 Python比较操作符.变量赋值.对象拷贝 1. 比较操作符 == 和 is 1.1 区别 1.2 实例 2. 变量及其赋值 2.1 概念和逻辑关系 ...