Spring AOP统一功能处理(切面、切点、连接点、通知)

news2024/9/26 3:32:09

目录

一、 AOP的一些前置知识

 1.1什么是Aop

1.2 AOP的作用 

1.3AOP基础组成 

 二、SpringAOP的实现

2.1添加SpringAOP框架支持

2.2定义切面(Aspect)

2.3定义切点(Pointcut)

2.4定义通知(Advice)

三、实例展示(计时器)

代码实现 


一、 AOP的一些前置知识

 1.1什么是Aop

Aop是一种统一处理某一问题的思想,比如验证用户是否登录

在为使用Aop的时候,我们需要验证的每个类(页面)都有调用验证方法,而使用了Aop后,我们只需要在某处把验证规则配置一下,就可以实现对需要验证的类的登录验证,不用每个类在重复调用验证方法了。

Aop由切面、切点、连接点、通知组成

切面表示我们要统一处理的功能(类)——比如验证用户是否登录
切点则是是否进行Aop拦截的规则(哪些页面不需要进行登录验证,哪些需要,这种规则)

连接点则是具体到哪些页面需要进行拦截(哪些类需要调用登录验证方法)
通知则是验证用户是否登录的那个具体方法实现(代码细节)——》前置通知,后置通知 

 

而AOP是一种思想,而SpringAOP是这个框架对AOP思想的实现(类似IoC和DI) 

1.2 AOP的作用 


想象一个场景,我们在做后台系统时,除了登录和注册等几个功能不需要做用户登录验证之外,其他几乎所有页面调用的前端控制器(Controller)都需要先验证用户登录的状态,那么这个时候我们要怎么处理呢?

如果不使用AOP,我们之前的处理方式是每个Controller都要写一遍用户登录验证,然而当你的功能越来越多,那么你要写的登录验证也越来越多,就有了很多重复的代码,而且这些方法的代码修改和维护的成本就会很高。

使用AOP,在进入业务代码之前进行统一的一个处理,去验证用户是否登录。

除了统一的用户登录判断之外,AOP还可以实现:

  • 统一日志记录
  • 统一方法执行时间统计
  • 统一的返回格式设置
  • 统一的异常处理
  • 事务的开启和提交

也就是说使用AOP可以扩充多个对象的某个能力,所以AOP可以说是OOP(Object Oriented Programming)面向对象编程的补充和完善。
 

1.3AOP基础组成 

AOP由以下四部分组成:

1.切面(Aspect):定义AOP业务类型(表示当前AOP是做什么的)。

2.连接点(Join Point):有可能调用AOP的地方就叫做一个连接点。

3.切点(Pointcut):定义AOP拦截规则。

4.通知(Advice)【增强方法】:定义什么时候干什么事(代码的实现细节,前后顺序)。

通知定义的是被拦截的方法具体要执行的业务,比如用户登录权限验证方法就是具体要执行的业务。

  • a) 前置通知:在拦截的目标方法之前执行的通知(事件)
  • b)后置通知:在拦截的目标方法之后执行的通知(事件)
  • c)返回之后通知:在拦截的目标方法返回数据之后通知
  • d)抛出异常之后的通知:在拦截的目标方法抛出异常之后执行的通知
  • e)环绕通知:在拦截方法执行前后都执行的通知。

AOP整个组成部分的概念如下图所示,以多个页面都要访问用户登录权限为例 

 


 二、SpringAOP的实现

2.1添加SpringAOP框架支持

在我们的项目的pom.xml中添加支持

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>

Spring AOP 框架, 在创建新项目的时候,搜索不到。
Spring Boot 项目中,有没有内置 AOP 框架。
这个时候,我们就需要借助 中央仓库了https://mvnrepository.com/ 

细节拓展: Spring AOP 依赖的版本号标签是可以省略的。
虽然 Spring AOP 没有 作为一个常用框架,导致我们引入框架的时候,需要借助 Maven 中央仓库来引入。
但是!Spring Boot 里面,其实有记录 Spring AOP 的 版本关联信息、
它可根据当前项目的环境,自动引入合适版本的 Spring AOP.

 


 

2.2定义切面(Aspect)

 

 

2.3定义切点(Pointcut)

其中pointcut方法为空方法,其不需要方法体,此方法名就是起到一个“标识”的作用,标识下面的通知方法具体指的是哪个切点。

 

 

切点表达式说明
AspectJ支持三种通配符

  • *:匹配任意字符,只匹配一个元素(包,类,或方法,方法参数)
  • ..:匹配任意字符,可以匹配多个元素,在表示类时,必须和*联合使用
  • +:表示按照类型匹配指定类的所有类,必须跟在类名后面,如com.cad.Car+,表示继承该类的所有子类包括本身

表达式示例如下:

  • execution(* com.example.demo.UserController. *(..)):匹配UserController类里的所有方法。
  • execution(* com.example.demo.UserController+.*(..)):匹配UserController类的子类包括该类的所有方法
  • execution(* com.example.demo.*.*(..)):匹配com.example.demo包下的所有类的所有方法
  • execution(* com.example.demo..*.*(..)):匹配com.example.demo包下、子孙包下所有类的所有方法
  • execution(* addUser(String,int)):匹配addUser方法,且第一个参数类型是String,第二个参数类型是int

2.4定义通知(Advice)

切点和通知的关系

 

Spring 切⾯类中,可以在⽅法上使⽤以下注解,设置⽅法为通知⽅法,在满⾜条件后会通知本⽅法进⾏调⽤:

  • 前置通知使⽤ @Before:通知⽅法会在⽬标⽅法调⽤之前执⾏。
  • 后置通知使⽤ @After:通知⽅法会在⽬标⽅法返回或者抛出异常后调⽤。
  • 返回之后通知使⽤ @AfterReturning:通知⽅法会在⽬标⽅法返回后调⽤。
  • 抛异常后通知使⽤ @AfterThrowing:通知⽅法会在⽬标⽅法抛出异常后调⽤。
  • 环绕通知使⽤ @Around:通知包裹了的⽅法(集合中的连接点),在被通知的⽅法收到通知之前和调⽤之后执⾏⾃定义的⾏为。

实现通知方法:在什么时机执行什么方法。
下面,我们以前置方法为例,演示一下。 

 


三、实例展示(计时器)

有的人学的不错,说:
我们可以在 其值方法中 加一行代码,记录 开始时间。
然后,再在 后置方法中 记录 结束时间。
最后,两者相减,不就得到了 拦截到的方法的执行时间了嘛!
这样做,真的对吗? 是不对。
这得看情况。

如果是在单线程的环境下(同一时刻,只有一个线程在访问该方法),使用上述方式,没有问题。


但是!
在多线程的情况下,有多个用户访问 会被拦截下来的方法,每一次访问,都会调用 前置方法。
这会导致, 前置方法记录的开始时间,会不停被刷新(覆盖),最终记录的是 最后一个线程访问的时间。
后置方法,也是同样的情况。


也就是说我们最终相减的情况:
哪一次的开始时间 减去 哪一次 结束时间,我们都是无从获知的!
而且,得出非常多,数量取决访问的线程有多少。

那么,问题来了!
前面我不是说: AOP 可以统⼀⽅法执⾏时间的统计嘛。
但是,遇到问题了、
那么,我们该怎么做呢?

.有的人可能会说:这是线程安全问题,加锁呗!
对不起,不行!这就是全局的问题,你加锁也解决不了问题。
但是!我们不是剩一个 环绕通知吗?
解决的办法,就在这里。

下面,我们就来先了解一下 环绕通知。
————————————————

环绕通知使⽤@Around:通知包裹了被通知的⽅法,在被通知的⽅法通知之前和调⽤之后执⾏⾃定义的⾏为。

形象来说:环绕通知,就是把 整个连接点(方法)包裹起来了,那我们就可以“为所欲为”了。


比如说:
我们执行的方法 是在当前通知里面去执行的,所以,我们就可以针对每一个方法去记录开始时间和结束时间。
因为在每一次在执行目标方法(连接点)和 通知 的时候,它们是在一块的。给人的感觉就像是具有了 事务的原子性

 

 

代码实现 

LoginAop代码 

package com.example.demo.aop;

import com.sun.corba.se.impl.ior.OldJIDLObjectKeyTemplate;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

// 切面表示我们要统一出来的问题——比如验证用户是否登录(LoginAop类)
// 切点则是是否进行Aop拦截的规则(哪些页面不需要进行登录验证,哪些需要,这种规则)
// 连接点则是具体到哪些页面需要进行拦截(登录验证)
// 通知则是验证用户是否登录的那个具体方法实现(代码细节)——》前置通知,后置通知
// 验证当前是否登录 的aop实现类
@Component
@Aspect // 表示当前类是一个切面
public class LoginAop {
    // 定义切点
    @Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
    public void pointcut() { // 标记切点
    }
    // 前置通知
    @Before("pointcut()") // 参数说明这个前置方法是针对与那个切点的
    public void doBefore() {
        System.out.println("前置通知");
    }
    // 后置通知
    @After("pointcut()")
    public void doAfter() {
        System.out.println("后置通知");
    }
    // 环绕通知
    @Around("pointcut()")
    public Object doAround(ProceedingJoinPoint joinPoint) {
        StopWatch stopWatch = new StopWatch();

        Object o =  null;
        System.out.println("环绕通知开始执行");
        try {
            stopWatch.start();
            o = joinPoint.proceed();
            stopWatch.stop();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("环绕通知结束执行");
        System.out.println("执行花费的时间: " + stopWatch.getTotalTimeMillis() + "ms");
        return o;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/170504.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

常用损失函数-交叉熵损失函数、MAE、MSE、smoothL1

目录标题常见的损失函数1、分类任务1.1 多分类任务1.2 二分类任务2、 回归任务2.1 MAE损失2.2 MSE损失2.3 smooth L1损失总结常见的损失函数 损失函数&#xff1a;衡量模型参数的质量的函数&#xff0c;衡量方式是比较网络输出和真实输出的差异。ybar与y 之间的差异 损失函数、…

Jtag_To_AXI的简单使用

文章目录基本操作其他基本操作 搭建的bd文件如下所示&#xff0c; 对tcl命令进行封装后&#xff0c;测试结果如下&#xff0c; 其他 网上看到JTAG to AXI Master的API函数读写操作这篇文章&#xff0c;试着复现一下&#xff0c;没成功&#xff0c;VS工程下的log文件显示打…

量子应用与未来市场:浅谈一下未来的发展方向

量子通信和量子网络 量子信息科学领域探索的是如何在量子系统中国将信息编码&#xff0c;包括量子力学的相关统计、存在的局限性和独特的可解释性&#xff0c;量子信息科学领域是量子计算、量子通信、量子传感的基础。量子通信的研发重点是在对信息进行量子编码之后&#xff0…

Long和Integer相互转换

目录一、int和long互相转换&#xff08;一&#xff09;long转化为int&#xff08;1&#xff09;类型强制转换&#xff08;2&#xff09;利用BigDecimal强制转换&#xff08;二&#xff09;int转化为long&#xff08;1&#xff09;类型强制转换&#xff08;2&#xff09;利用Big…

【go语言http2.0client源码分析】

go语言之http2.0client源码分析client.GetNewRequestdo requesthttp2.Transport.RoundTripGetClientConnnewClientConnReadFrameprocessHeaderswrite request上一篇分析了http2.0的实现之后,这里分析一下client的实现。 package mainimport ("crypto/tls""cryp…

第二层:对象的初始化和清理

文章目录前情回顾对象特性——对象的初始化和清理构造函数和析构函数什么是构造函数和析构函数构造函数构造函数的语法构造函数的分类按照参数分类按照类型分类拷贝构造函数拷贝函数的调用时机深拷贝和浅拷贝构造函数的调用方法括号法显示法隐式转换法构造函数规则析构函数析构…

DM8:达梦数据库DEM--dmagent监控服务器代理部署(详细步骤)

DM8:达梦数据库DEM部署dmagent代理环境&#xff08;详细步骤&#xff09;1 dmagent代理下载部署1.1通过web DEM下载代理包1.2 从数据库服务器目录直接拷贝dmagent2 部署JDK环境2.1 使用数据库自带的JDK包2.2 配置服务器JDK环境变量3 配置agent.ini文件3.1 103 节点 &#xff0c…

C语言——运算符与表达式

一、赋值运算符 运算符描述实例将右边操作数的值赋给左边操作数AB,即将B的值赋给A加法赋值运算符&#xff0c;将右边操作数加上左边操作数的结果赋值给左边操作数B A 等价于 B B A-减法赋值运算符&#xff0c;将左边操作数减去右边操作数的结果赋值给左边操作数B - A 等价于…

擎创动态 | 酸了酸了,这年会也忒燃了吧

前言&#xff1a;受疫情影响的这一年里&#xff0c;擎创科技逆流勇上&#xff0c;汇聚点点星火&#xff0c;点亮新的征程。擎创的服务随之正式遍及全国&#xff0c;北起重工业基地的东三省&#xff0c;南至改革开放最早的粤港澳大湾区&#xff0c;东起经济中心的大本营上海&…

数据开发面试问题记录

因作者近期正在投递数据开发岗位&#xff0c;所以会在此记录一些面试过程中的问题&#xff0c;持续更新&#xff0c;直到入职新公司为止 1. 数仓建模的三范式理论 所谓的范式&#xff0c;就是我们在关系建模的时候所遵从的一些规范&#xff0c;而三范式&#xff0c;指的就是三…

QML工程之初始工程代码分析

接着上一讲&#xff0c;当建立完工程之后&#xff0c;IDE 会呈现如下的界面下面的代码是main.cpp&#xff0c;工程起始运行的代码段&#xff0c;具体的函数说明都在代码段里面进行了标注。#include <QGuiApplication> //主要是ui进程运行头函数&#xff0c;包含事件循环&…

寻找数组的中心下标

Python-寻找数组的中心下标 题目 给你一个整数数组 nums &#xff0c;请计算数组的 中心下标 。 数组 中心下标 是数组的一个下标&#xff0c;其左侧所有元素相加的和等于右侧所有元素相加的和。 如果中心下标位于数组最左端&#xff0c;那么左侧数之和视为 0 &#xff0c;因…

佳讯频传!安全狗多项能力获信通院认可

近期&#xff0c;信通院发布了其主导的《基于云的工作负载保护平台能力要求》标准以及《零信任产业图谱》。 作为国内云原生安全领导厂商&#xff0c;安全狗也凭借自身综合且突出的安全能力获得信通院认可。 厦门服云信息科技有限公司&#xff08;品牌名&#xff1a;安全狗&a…

【SpringBoot高级篇】SpringBoot集成RocketMQ消息队列]

【SpringBoot高级篇】SpringBoot集成RocketMQ消息队列]RocketMQ简介技术架构基本概念Docker环境安装RocketMQrocketmq-client消息发送基本样例消息发送发送同步消息发送异步消息单向发送消息消费消息负载均衡模式广播模式顺序消息顺序消息生产顺序消费消息延时消息启动消息消费…

基于M实现的JWT解决方案

文章目录基于M实现的JWT解决方案简介现状原理JWT 组成结构头部Header有效载荷Payload哈希签名SignatureJWT完整结果JWT基于M的使用流程总结完整代码基于M实现的JWT解决方案简介JWT 英文名是 Json Web Token &#xff0c;是一种用于通信双方之间传递安全信息的简洁的、URL安全的…

2023年,PMP认证考试的心得分享

对于刚开始要准备参加PMP考试的人&#xff0c;大多应该都是不知道怎么去考试复习好的。PMP认证考试虽是美国的考试&#xff0c;但其实这跟国内其它的考试复习也差不多&#xff0c;没有什么很特别之处&#xff0c;只是多了一个中英互译&#xff0c;再就是学习的内容不一样&#…

windows系统中环境系统变量和用户变量的区别

前言 -- 什么是环境变量一般我们安装软件之后&#xff0c;为了能够在cmd命令行运行软件&#xff0c;一般都需要设置一下环境变量&#xff0c;否则就会出现找不相关命令的错误提示。所谓环境变量&#xff0c;可以简单理解为就是给操作系统定义的一些路径和名称。比如使用最常使用…

个人对粗糙集的一些理解和简单举例

文章目录1、 数据价值密度低的解决方案1.1 粗糙集中对应的概念&#xff1a;属性约简1.2 属性约简的好处1.3 粗糙集的应用2、粗糙集的简介--->原理2.1 粗糙集的概念2.2 从例子看粗糙集2.3 粗糙集模型的分类及其评估标准3、粗糙集的主要研究方向3.1 模型创新3.2 属性约简3.3 提…

浅析正则表达式+范围规则校验表达式+js从字符串中截取数字

平时项目中经常需要用到正则表达式&#xff0c;可惜之前太懒(当然最主要是太菜也不会写)都是直接网上搜。之前用的也简单&#xff0c;无非是校验手机号码格式、校验邮箱格式、偶尔有校验密码这种&#xff0c;网上一搜一大堆&#xff0c;根本不用自己写&#xff0c;结果前段时间…

【ONE·C || 函数与数组】

总言 C语言&#xff1a;函数、数组初步认识。 文章目录总言1、函数1.1、是什么1.1.1、基本介绍1.1.2、库函数使用演示(strcpy、memset)1.1.3、自定义函数使用演示1.2、函数参数、传值调用和传址调用1.3、相关练习1.3.1、写一个函数&#xff1a;可以判断一个数是不是素数1.3.2、…