当前位置: 首页 > news >正文

浅谈 Spring AOP框架 (1)

文章目录

  • 一、什么是 Spring AOP
  • 二、为什么要使用 Spring AOP
  • 三、AOP 的一些应用场景
  • 四、AOP 的组成
  • 五、如何使用 Spring AOP
  • 六、Spring AOP 的实现原理
    • 6.1、JDK 和 CGLIB 的区别

一、什么是 Spring AOP

AOP (Aspect Oriented Programming) :面向切面编程,它是一种思想,是对某一类事情(某一类问题)的集中处理。而 Spring AOP 是一个框架, 提供了一种对AOP思想的实现,它们的关系和 loC 与 DI 类似。

二、为什么要使用 Spring AOP

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

之前的处理方式:每个 Controller 都要写一遍用户登录验证,但当实现的功能越来越多时,要写的登录验证也越来越多,但其实这些登陆验证的方法又是相同的,这些相同的方法就会冗余的存在项目的各个地方,导致代码修改和维护的成本很高。

这时候我们对于这种功能统一,且使用的地方较多的功能,就可以考虑使用 AOP 来统一处理

就像之前我们使用 Spring 来写项目时,就需要额外安装 Tomcat 才能将项目在浏览器上运行起来;后来我们使用 SpringBoot 写项目,SpringBoot 已经内置好了Tomcat,我们就不需要额外安装 Tomcat 也能将项目在浏览器上运行起来。其实都是需要Tomcat来给项目的运行提供支持,但Spring是需要手动安装,而SpringBoot直接内置好了,我们开发时就比较轻松、省事。

对于 Spring AOP 来说也是一样,在没有使用Spring AOP之前,像我们写的一些管理系统,一般除了登录、注册页面能够在未登录之前访问,其他界面都是要求登陆后用户含有权限时才能访问,因此我们需要在项目里多个地方都要各自实现或调用用户验证的方法,但使用了Spring AOP之后,我们只需要在某一处配置一下,所有需要判断用户登录页面(中的方法)就全部可以实现用户登录验证了,不再需要每个方法中都写相同的用户登录验证了,给我们带来了轻松、省事。

三、AOP 的一些应用场景

(1)、统一的用户登录判断
(2)、统一日志记录
(3)、统一方法执行时间统计
可以拿到所有执行的方法的执行时间,可以很快的找到执行时间较慢的方法进行优化。
(4)、统一的返回格式设置
(5)、统一的异常处理
(6)、事务的开启和提交等

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

四、AOP 的组成

(1)、切面(Aspect)
    切面(Aspect)由切点(Pointcut)和通知(Advice)组成,它既包含了横切逻辑的定义,也包括了连接点的定义。

    即切面是包含了:通知、切点和切面的类,相当于AOP 实现的某个功能的集合。

    通俗的理解切面:在程序中就是一个处理某个具体问题的一个类。类里面包含了很多方法,这些方法就是切点和通知。

(2)、切点(Pointcut)
    切点相当于保存了众多连接点的一个集合(如果把切点看成一个表,而连接点就是表中一条一条的数据)。

    通俗的理解切点:用来配置程序进行主动拦截的规则。

    其实用户在地址栏输入一个URL时,如果这个URL不是登录或注册,此时用户的请求就会被程序拦截,这个拦截不是说用户手动调用去拦截的,而是程序感知到这个请求,程序主动去拦截的,那想要程序能够具备主动拦截的能力,我们需要去配置,那么怎么配置,配置的规则是怎么样的,就是切点的工作。

(3)、通知(Advice)
    切面也是有目标的——>它必须完成的工作。在 AOP 术语中,切面的工作被称之为通知。

    通俗的理解通知:程序中被拦截的请求其触发的具体动作(即被拦截的请求它触发到的方法是做什么事)。就是在通知中实现具体的业务代码。通知就是切面(类)里的方法。

通知分为5类:
a.前置通知
    注解是 @Before
    在执行目标方法之前执行的方法叫做前置通知。
b.后置通知
    注解是 @After
    在执行了目标方法之后执行的方法就叫做后置通知。
c.异常通知
    注解是@AfterThrowing
    目标方法在执行时出现了异常时,执行的通知。
d.返回通知
    注解是@AfterReturning
    目标方法返回数据(return)时,执行的通知。
e.环绕通知
    注解是 @Around
    在目标方法执行的周期范围内(执行之前、执行中、执行后)都可以执行的方法叫做环绕通知。
(4)、连接点(Join Point)
可能会触发 AOP 规则的所有点(所有请求)。

五、如何使用 Spring AOP

(1)、添加 Spring AOP 框架的依赖
在这里插入图片描述

(2)、定义切面(创建切面类)
在这里插入图片描述

(3)、定义切点(配置拦截规则)
在这里插入图片描述
Aspect 支持三种通配符:
*           匹配任意字符,只匹配一个元素(包,类,或方法,方法参数)
..           匹配任意字符,可以匹配多个元素,在表示类时,必须和*联合使用

+           表示按照类型匹配指定类的所有类,必须跟在类名后面,如com.cad.Car+,表示继承该类的所有子类,包括本身。

切点细节解析:
切点表达式由切点函数组成,其中execution()是最常用的切点函数,用来匹配方法,语法为:
execution(<修饰符><返回类型><包.类.方法(参数)><异常>)

修饰符,一般省略:
public    公共方法
*            任意

返回类型,不能省略:
void        返回没有值
String      返回值字符串
*              任意

包:
com.gyf.crm                      固定包
com.gyf.crm.*.service       crm包下面子包任意(例如:com.gyf.crm.staff.service)
com.gyf.crm…                  crm包下面的所有子包(含自己)
com.gyf.crm.*.service…    crm包下面任意子包,固定目录service,service目录任意包

类:
UserServiceImpl               指定类
*Impl                                 以Impl结尾

User *                                以User开头

*                                         任意

方法名,不能省略:
addUser                             固定方法
add*                                   以add开头
*Do                                    以Do结尾

*                                         任意

(参数):
()                                         无参
(int)                                     一个整型
(int,int)                                 两个
(..)                                      参数任意

throws,可省略,一般不写

(4)、定义通知的实现
在这里插入图片描述

Spring AOP项目例子链接。

六、Spring AOP 的实现原理

Spring AOP 是构建在动态代理的基础上,因此Spring 对 AOP 的支持局限于方法级别的拦截。

静态代理:编码阶段,即程序运行之前就确定的代理。
动态代理:程序运行时产生的代理。

Spring AOP 支持 JDK Proxy 和 CGLIB 方式实现动态代理。

默认情况下,实现了接口的类,使用 AOP 会基于JDK 生成代理类;没有实现接口的类,会基于 CGLIB 生成代理类。

织入:代理的生成时机
什么阶段下生成的代理对象,叫做织入。有编译器、类加载期、运行期(Spring AOP)。

6.1、JDK 和 CGLIB 的区别

(1)、JDK实现,要求被代理类必须实现接口,之后是通过 InvocationHandler 及 Proxy ,在运行时动态的在内存中生成了代理类对象,该代理对象是通过实现同样的接口实现(类似静态代理接口实现的方式),只是该代理类是在运行期时,动态的织入统一的业务逻辑字节码来完成。
(2)、 CGLIB实现,被代理类可以不实现接口,是通过继承被代理类,在运行时动态的生成代理类对象。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 数据湖之Hudi
  • Java 技巧:将整数每一位数字转换为数组
  • 【C++题解】1015. 鸡兔同笼问题
  • ABAQUS基于CT断层扫描的三维圆柱体多孔结构建模
  • 【LabVIEW学习篇 - 12】:通知器
  • 数据挖掘可以挖掘什么类型的模式?
  • ReentrantLock源码分析
  • QChart曲线绘制-1.普通曲线
  • 数据结构——双链表详解(超详细)
  • git学习入门1——下载安装与添加用户标识设置name与Email
  • 音频重采样基本流程
  • MybatisPlus对象注释规则笔记
  • Dubbo源码深度解析(二)
  • MySQL 保姆级教程(十五): 组合查询
  • C语言指针·高级用法超详解(指针运算、野指针、悬空指针、void类型指针、二级以及多级指针)
  • 【跃迁之路】【519天】程序员高效学习方法论探索系列(实验阶段276-2018.07.09)...
  • Angular2开发踩坑系列-生产环境编译
  • Java|序列化异常StreamCorruptedException的解决方法
  • java正则表式的使用
  • JS基础篇--通过JS生成由字母与数字组合的随机字符串
  • mac修复ab及siege安装
  • PaddlePaddle-GitHub的正确打开姿势
  • Python 基础起步 (十) 什么叫函数?
  • Spark in action on Kubernetes - Playground搭建与架构浅析
  • Swift 中的尾递归和蹦床
  • Synchronized 关键字使用、底层原理、JDK1.6 之后的底层优化以及 和ReenTrantLock 的对比...
  • Vue 2.3、2.4 知识点小结
  • 不用申请服务号就可以开发微信支付/支付宝/QQ钱包支付!附:直接可用的代码+demo...
  • 面试题:给你个id,去拿到name,多叉树遍历
  • 使用 @font-face
  • 使用 QuickBI 搭建酷炫可视化分析
  • 思否第一天
  • 新版博客前端前瞻
  • 国内唯一,阿里云入选全球区块链云服务报告,领先AWS、Google ...
  • ​Z时代时尚SUV新宠:起亚赛图斯值不值得年轻人买?
  • #{}和${}的区别是什么 -- java面试
  • #if等命令的学习
  • #Z0458. 树的中心2
  • (16)UiBot:智能化软件机器人(以头歌抓取课程数据为例)
  • (2020)Java后端开发----(面试题和笔试题)
  • (k8s)Kubernetes 从0到1容器编排之旅
  • (Matlab)基于蝙蝠算法实现电力系统经济调度
  • (NSDate) 时间 (time )比较
  • (第30天)二叉树阶段总结
  • (第9篇)大数据的的超级应用——数据挖掘-推荐系统
  • (分布式缓存)Redis哨兵
  • (附源码)springboot“微印象”在线打印预约系统 毕业设计 061642
  • (附源码)springboot码头作业管理系统 毕业设计 341654
  • (回溯) LeetCode 78. 子集
  • (蓝桥杯每日一题)love
  • (十)DDRC架构组成、效率Efficiency及功能实现
  • (十八)SpringBoot之发送QQ邮件
  • (学习日记)2024.04.10:UCOSIII第三十八节:事件实验
  • (一一四)第九章编程练习
  • (转)Linux整合apache和tomcat构建Web服务器