Spring的另一大的特征:AOP

2024-02-26 06:44
文章标签 java spring 特征 aop 一大

本文主要是介绍Spring的另一大的特征:AOP,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • AOP (Aspect Oriented Programming)
  • AOP 入门案例(注解版)
  • AOP 工作流程——代理
  • AOP切入点表达式
  • AOP 通知类型
  • AOP通知获取数据
    • 获取切入点方法的参数
    • 获取切入点方法返回值
    • 获取切入点方法运行异常信息
  • 百度网盘分享链接输入密码数据错误兼容性处理

AOP (Aspect Oriented Programming)

  • AOP (Aspect Oriented Programming) 面向切面编程 ,指导开发者如何组织程序结构

OOP (Object Oriented Programming) 面向对象编程

  • AOP 的作用: 在不惊动原始设计的基础上为其进行功能增强
  • Spring 理念: 无入侵式/无侵入式

在这里插入图片描述

  • 连接点(JointPoint): 程序执行过程中的任意位置,粒度为执行方法、抛出异常、设置变量等。

    • 在 SpringAOP 中,理解为方法的执行
  • 切入点(Pointcut): 匹配连接点的式子

    • 在 SpringAOP 中,一个切入点可以只描述一个具体方法,也可以匹配多个方法
      • 一个具体方法:eg : com.itheima.dao包下的BookDao接口中的无形参无返回值的save方法
      • 匹配多个方法:eg : 所有的save方法,所有的get开头的方法,所有以Dao结尾的接口中的任意方法,所有带有一个参数的方法
  • 通知(Advice): 在切入点处执行的操作,也就是共性功能

    • 在 SpringAOP 中,功能最终以方法的形式呈现
  • 通知类: 定义通知的类

  • 切面(Aspect): 描述通知与切入点的对应关系

AOP 入门案例(注解版)

- 导入 aop 相关坐标
    <dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.4</version></dependency>

spring-context 坐标依赖 spring-aop 坐标
在这里插入图片描述

    • 定义dao 接口与实现类
public interface BookDao {public void save();public void update();public void delete();public void select();
}
@Repository
public class BookDaoImpl implements BookDao {public void save() {//记录程序当前执行执行(开始时间)Long startTime = System.currentTimeMillis();//业务执行万次for (int i = 0;i<10000;i++) {System.out.println("book dao save ...");}//记录程序当前执行时间(结束时间)Long endTime = System.currentTimeMillis();//计算时间差Long totalTime = endTime-startTime;//输出信息System.out.println("执行万次消耗时间:" + totalTime + "ms");}public void update(){System.out.println("book dao update ...");}public void delete(){System.out.println("book dao delete ...");}public void select(){System.out.println("book dao select ...");}
}
    • 定义通知类,制作通知
    • 定义切入点:切入点定义依托一个不具有实际意义的方法进行,即无参数,无返回值,方法体无实际逻辑
    • 绑定切入点与通知关系,并指定通知添加到原始连接点的具体执行位置
    • 定义通知类受Spring容器管理,并定义当前类为切面类
@Component
@Aspect
public class MyAdvice {@Pointcut("execution(* com.itheima.dao.BookDao.*d*(..))")private void pt(){}@Around("pt()")public Object around(ProceedingJoinPoint pjp) throws Throwable {System.out.println("------------------------------");Long startTime = System.currentTimeMillis();for (int i = 0 ; i<10000 ; i++) {//调用原始操作pjp.proceed();}Long endTime = System.currentTimeMillis();Long totalTime = endTime-startTime;System.out.println("执行万次消耗时间:" + totalTime + "ms");return null;}}
    • 开启 Spring 对 AOP 注解驱动支持 : @EnableAspectJAutoProxy
@Configuration
@ComponentScan("com.itheima")
@EnableAspectJAutoProxy
public class SpringConfig {
}

AOP 工作流程——代理

  1. Spring 容器启动
  2. 读取所有切面配置中的切入点
  3. 初始化bean,判定bean对应的类中的方法是否匹配到任意切入点
    • 匹配失败,创建对象
    • 匹配成功,创建原始对象(目标对象)的代理对象
  4. 获取bean执行方法
    • 获取bean,调用方法并执行,完成操作
    • 获取bean是代理对象时, 根据代理对象的运行模式运行原始方法与增强的内容,完成操作
  • 目标对象(Target) : 原始功能去掉共性功能对应的类产生的对象,这种对象是无法直接完成最终工作的。
  • 代理(Proxy) : 目标对象无法直接完成工作,需要对其进行功能回填,通过原始对象的代理对象实现

AOP切入点表达式

  • 切入点:要进行增强的方法
  • 切入点表达式:要进行增强的方法的描述方式

在这里插入图片描述

  • 切入点表达式标准格式: 动作关键字 (访问修饰符 返回值 包名.类/接口名.方法名(参数)异常名)
execution (public User com.itheima.service.UserService.findById (int))
    • 动作关键字: 描述切入点的行为动作,例如execution表示执行到指定切入点
    • 访问修饰符: public , private 等 可省略
    • 返回值
    • 包名
    • 类/接口名
    • 方法名
    • 参数
    • 异常名:方法定义中抛出指定异常,可省略
  • 可以使用通配符描述切入点,快速描述:

    • eg: * : 单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现
execution (public * com.itheima.*.UserService.find* (*))

匹配com.itheima包下的任意包中的UserService类或接口中所有find开头的带有一个参数的方法

    • eg: . . :多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写
execution (public User com..UserService.findById (..))

匹配com包下的任意包中的UserService类或接口中所有名称为findByld的方法

    • eg: + :专用于匹配子类类型
execution (* *..*Service+.*(..))

AOP 通知类型

  • AOP 通知描述了抽取的共性功能,根据共性功能抽取的位置不同,最终运行代码时要将其加入到合理的位置
  • 5 种类型
    • 前置通知
    • 后置通知
    • 环绕通知 (重点) :通过ProceedingJoinPoint 对原始方法调用,获得返回值,最终返回这个返回值
    • 返回后通知 (了解)
    • 抛出异常后通知 (了解)
@Pointcut("execution(void com.itheima.dao.BookDao.update())")private void pt(){}@Pointcut("execution(int com.itheima.dao.BookDao.select())")private void pt2(){}//@Before:前置通知,在原始方法运行之前执行
//    @Before("pt()")public void before() {System.out.println("before advice ...");}//@After:后置通知,在原始方法运行之后执行
//    @After("pt2()")public void after() {System.out.println("after advice ...");}//@Around:环绕通知,在原始方法运行的前后执行
//    @Around("pt()")public Object around(ProceedingJoinPoint pjp) throws Throwable {System.out.println("around before advice ...");//表示对原始操作的调用Object ret = pjp.proceed();System.out.println("around after advice ...");return ret;}//    @Around("pt2()")public Object aroundSelect(ProceedingJoinPoint pjp) throws Throwable {System.out.println("around before advice ...");//表示对原始操作的调用Integer ret = (Integer) pjp.proceed();System.out.println("around after advice ...");return ret;}//@AfterReturning:返回后通知,在原始方法执行完毕后运行,且原始方法执行过程中未出现异常现象
//    @AfterReturning("pt2()")public void afterReturning() {System.out.println("afterReturning advice ...");}//@AfterThrowing:抛出异常后通知,在原始方法执行过程中出现异常后运行@AfterThrowing("pt2()")public void afterThrowing() {System.out.println("afterThrowing advice ...");}
}
  • @Around 注意事项
    • 环绕通知必须依赖形参 ProceedingJoinPoint 才能实现对原始方法的调用,进而实现原始方法调用前后同时添加通知
    • 通知中如果未使用 ProceedingJoinPoint 对原始方法进行调用将跳过原始方法的执行
    • 对原始方法的调用可以不接收返回值,通知方法设置成void即可,如果接收返回值,必须设定为Object类型
    • 原始方法的返回值如果是void类型,通知方法的返回值类型可以设置成void,也可以设置成Object
    • 由于无法预知原始方法运行后是否会抛出异常,因此环绕通知方法必须抛出Throwable对象

AOP通知获取数据

获取切入点方法的参数

  • JoinPoint: 适用于前置、后置、返回后、抛出异常后通知
  • JoinPoint 对象描述了连接点方法的运行状态,可以获取到原始方法的调用参数
	@Before("pt()")public void before(JoinPoint jp) {Object[] args = jp.getArgs();System.out.println(Arrays.toString(args));System.out.println("before advice ..." );}
  • ProceedJoinPoint: 适用于环绕通知, 是 JoinPoint 的子类
	@Around("pt()")public Object around(ProceedingJoinPoint pjp) throws Throwable{Object[] args = pjp.getArgs();System.out.println(Arrays.toString(args));ret = pjp.proceed(args);return ret;}

获取切入点方法返回值

  • 返回后通知
    //设置返回后通知获取原始方法的返回值,要求returning属性值必须与方法形参名相同@AfterReturning(value = "pt()",returning = "ret")public void afterReturning(JoinPoint jp, String ret) {System.out.println("afterReturning advice ..."+ret);}
  • 环绕通知 可以手工书写对原始方法的调用,得到的结果即为原始方法的返回值。
	@Around("pt()")public Object around(ProceedingJoinPoint pjp) throws Throwable{ret = pjp.proceed(args);return ret;}

获取切入点方法运行异常信息

  • 抛出异常后通知:可以获取切入点方法中出现的异常信息,使用形参可以接收对应的异常对象
    //设置抛出异常后通知获取原始方法运行时抛出的异常对象,要求throwing属性值必须与方法形参名相同@AfterThrowing(value = "pt()",throwing = "t")public void afterThrowing(Throwable t) {System.out.println("afterThrowing advice ..."+t);}
  • 环绕通知
	@Around("pt()")public Object around(ProceedingJoinPoint pjp) {Object ret = null;try {ret = pjp.proceed(args);} catch (Throwable t) {t.printStackTrace();}return ret;}

百度网盘分享链接输入密码数据错误兼容性处理

@Around("DataAdvice.servicePt()")
public Object trimString(ProceedingJoinPoint pjp) throws Throwable {Object[] args = pjp.getArgs();//对原始参数中的每一个参数进行操作for (int i = 0; i < args.length; i++) {if (args[i].getClass().equals(String.class)) {args[i] = args[i].toString().trim();}}return pjp.proceed(args);
}

这篇关于Spring的另一大的特征:AOP的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/747978

相关文章

SpringBoot多环境配置数据读取方式

《SpringBoot多环境配置数据读取方式》SpringBoot通过环境隔离机制,支持properties/yaml/yml多格式配置,结合@Value、Environment和@Configura... 目录一、多环境配置的核心思路二、3种配置文件格式详解2.1 properties格式(传统格式)1.

Apache Ignite 与 Spring Boot 集成详细指南

《ApacheIgnite与SpringBoot集成详细指南》ApacheIgnite官方指南详解如何通过SpringBootStarter扩展实现自动配置,支持厚/轻客户端模式,简化Ign... 目录 一、背景:为什么需要这个集成? 二、两种集成方式(对应两种客户端模型) 三、方式一:自动配置 Thick

Spring WebClient从入门到精通

《SpringWebClient从入门到精通》本文详解SpringWebClient非阻塞响应式特性及优势,涵盖核心API、实战应用与性能优化,对比RestTemplate,为微服务通信提供高效解决... 目录一、WebClient 概述1.1 为什么选择 WebClient?1.2 WebClient 与

Java.lang.InterruptedException被中止异常的原因及解决方案

《Java.lang.InterruptedException被中止异常的原因及解决方案》Java.lang.InterruptedException是线程被中断时抛出的异常,用于协作停止执行,常见于... 目录报错问题报错原因解决方法Java.lang.InterruptedException 是 Jav

深入浅出SpringBoot WebSocket构建实时应用全面指南

《深入浅出SpringBootWebSocket构建实时应用全面指南》WebSocket是一种在单个TCP连接上进行全双工通信的协议,这篇文章主要为大家详细介绍了SpringBoot如何集成WebS... 目录前言为什么需要 WebSocketWebSocket 是什么Spring Boot 如何简化 We

java中pdf模版填充表单踩坑实战记录(itextPdf、openPdf、pdfbox)

《java中pdf模版填充表单踩坑实战记录(itextPdf、openPdf、pdfbox)》:本文主要介绍java中pdf模版填充表单踩坑的相关资料,OpenPDF、iText、PDFBox是三... 目录准备Pdf模版方法1:itextpdf7填充表单(1)加入依赖(2)代码(3)遇到的问题方法2:pd

Java Stream流之GroupBy的用法及应用场景

《JavaStream流之GroupBy的用法及应用场景》本教程将详细介绍如何在Java中使用Stream流的groupby方法,包括基本用法和一些常见的实际应用场景,感兴趣的朋友一起看看吧... 目录Java Stream流之GroupBy的用法1. 前言2. 基础概念什么是 GroupBy?Stream

SpringBoot监控API请求耗时的6中解决解决方案

《SpringBoot监控API请求耗时的6中解决解决方案》本文介绍SpringBoot中记录API请求耗时的6种方案,包括手动埋点、AOP切面、拦截器、Filter、事件监听、Micrometer+... 目录1. 简介2.实战案例2.1 手动记录2.2 自定义AOP记录2.3 拦截器技术2.4 使用Fi

最新Spring Security的基于内存用户认证方式

《最新SpringSecurity的基于内存用户认证方式》本文讲解SpringSecurity内存认证配置,适用于开发、测试等场景,通过代码创建用户及权限管理,支持密码加密,虽简单但不持久化,生产环... 目录1. 前言2. 因何选择内存认证?3. 基础配置实战❶ 创建Spring Security配置文件

Spring Security 单点登录与自动登录机制的实现原理

《SpringSecurity单点登录与自动登录机制的实现原理》本文探讨SpringSecurity实现单点登录(SSO)与自动登录机制,涵盖JWT跨系统认证、RememberMe持久化Token... 目录一、核心概念解析1.1 单点登录(SSO)1.2 自动登录(Remember Me)二、代码分析三、