目录

一、 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;}
}

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

  1. Spring Boot 统一功能处理(用户登录权限效验-拦截器、异常处理、数据格式返回)

    文章目录 1. 统一用户登录权限效验 1.1 最初用户登录权限效验 1.2 Spring AOP 统一用户登录验证 1.3 Spring 拦截器 1.4 练习:登录拦截器 1.5 拦截器实现原理 1. ...

  2. 利用spring aop统一处理异常和打日志

    利用spring aop统一处理异常和打日志 spring aop的概念,很早就写博客介绍了,现在在工作中真正使用. 我们很容易写出的代码 我们很容易写出带有很多try catch 和 logger. ...

  3. Spring Boot 统一功能处理

    Spring Boot 统一功能处理 一.使用 Spring 拦截器来实现登录验证 引入 代码实现 步骤1 自定义拦截器 步骤2 添加拦截器并设置拦截规则 拦截规则 步骤3 创建前后端交互,用于测试 ...

  4. 编程小白入门分享三:Spring AOP统一异常处理

    编程小白入门分享三:Spring AOP统一异常处理 参考文章: (1)编程小白入门分享三:Spring AOP统一异常处理 (2)https://www.cnblogs.com/lxk12345/p ...

  5. Spring AOP 源码分析 - 筛选合适的通知器

    1.简介 从本篇文章开始,我将会对 Spring AOP 部分的源码进行分析.本文是 Spring AOP 源码分析系列文章的第二篇,本文主要分析 Spring AOP 是如何为目标 bean 筛选出 ...

  6. spring aop 统一捕获异常

    SpringAOP简介 面向切面编程(Aspect Oriented Programming)提供了另一种角度来思考程序的结构,通过这种方式弥补面向对象编程(Object Oriented Progr ...

  7. Spring AOP编程-传统基于aspectJ切点AOP开发

    1.在配置文件上方增加aop相关配置. 2.在spring的配置文件中定义目标与通知. 3.使用aop:xxx标签来完成切面与切点声明. 4.我们使用aspectj的切面声明方式 需要在导入aspec ...

  8. spring aop统一进行日常及异常的处理

    什么是AOP 以下摘自百度百科: 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.A ...

  9. 史上最烂 spring aop 原理分析

    盗引·中篇·spring aop spring aop: jdk 动态代理和 cglib 动态代理的特点.区别.使用方式.原理及各自对反射的优化.二者在 spring 中的统一.通知顺序.从 @Asp ...

最新文章

  1. 软件分享大会之Bonny使用感想
  2. 水晶易表调用C#的WebService,返回数据集合
  3. java ee的小程序_扩展Java EE应用程序的基础
  4. kafka中topic默认属性_分享:Kafka 的 Lag 计算误区及正确实现
  5. 博弈——通过博弈思想解决的问题(hdu1847,2147)
  6. 茂名2021高考成绩查询入口,茂名高考成绩查询入口
  7. 基于Jenkins的嵌入式软件持续集成方法
  8. EmWin 接触---基础函数
  9. oracle adg 人工干预,Oracle DataGuard
  10. 888. 公平的糖果棒交换
  11. python中文聊天机器人_[源码和文档分享]基于python的中文聊天机器人
  12. java编写Linux文件共享,ubuntu下用samba实现windows与linux文件共享
  13. POI中设置Excel单元格格式样式(居中,字体,边框等)
  14. Android支付实践(三)之银联支付功能(客户端+服务端)
  15. 安卓 实现一个简单的计算器
  16. 心理测评全系统设计与代码实现
  17. 配置 Android 的 SDK, DNK, JDK, ANT 环境
  18. [luogu] P1682 过家家 并查集
  19. uniny 物体运动到一个点停止_unity控制运动
  20. 北京积分落户纳税入库时间余额已不足

热门文章

  1. 第一节项目整体管理学习笔记
  2. vue接入点聚weboffice打开在线文档报系统错误
  3. 指划王孔小兵:Testin云测助益亲子类APP实现年轻家庭和谐
  4. 树莓派远程控制(kali)
  5. java计算机毕业设计工厂生产计划与进度管理系统源码+mysql数据库+系统+lw文档+部署
  6. libgdx和android界面结合,Android游戏引擎libgdx使用教程11:Skin和UI配置文件
  7. 滥用 ESI 详解(上)
  8. PHP友盟 接口推送,友盟推送文档接口json格
  9. Android集成友盟推送
  10. Java编程基础(3)——字典类型