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

Spring第七天(AOP)

简介

AOP(Aspect Oriented Programing)面向切面编程,一种编程范式,指导开发者如何组织程序结构

作用

不惊动原始设计的基础上为其进行功能增强

Spring理念:无入侵式/无侵入式

基本概念

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

        在SpringAOP中,理解为方法的执行

切入点(Pointcut) : 匹配连接点的式子

        在SpringAOP中,一个切入点只描述一个具体方法,也可以匹配多个方法

                一个具体方法:e.g.:dao类中的save方法

                匹配多个方法:所有的save方法,所有以get开头的方法,所有以Dao结尾的接口中的任                  意方法,所有带有一个参数的方法

通知(Advice) : 在切入点执行的操作,也就是共性功能

        在SpringAOP中,功能最终以方法的形式呈现

通知类:定义通知的类

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

实现案例

第一步、导入相关坐标

    <dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.10.RELEASE</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.4</version></dependency></dependencies>

第二步、定义dao接口与其实现类

package com.cacb.dao.impl;import com.cacb.dao.BookDao;
import org.springframework.stereotype.Repository;@Repository
public class BookDaoImpl implements BookDao {@Overridepublic void save() {System.out.println(System.currentTimeMillis());System.out.println("BookDao saving!");}@Overridepublic void update() {System.out.println("BookDao updating!");}
}

第三步、定义通知类,制作通知

public class MyAdvice {public void method(){System.out.println(System.currentTimeMillis());}
}

第四步、在通知类中定义切入点

public class MyAdvice {@Pointcut("execution(void com.cacb.dao.BookDao.update())")private void pt(){}public void method(){System.out.println(System.currentTimeMillis());}
}

注:

切入点定义依托一个不具有实际意义的方法进行,即无参数,无返回值,方法体无实际逻辑

第五步、在通知类中绑定切入点预通知关系,并指定通知添加到原始连接点的具体执行位置

public class MyAdvice {@Pointcut("execution(void com.cacb.dao.BookDao.update())")private void pt(){}@Before("pt()")public void method(){System.out.println(System.currentTimeMillis());}
}

第六步、定义通知类受Spring容器管理,并定义当前类为切面类 

@Component
@Aspect
public class MyAdvice {@Pointcut("execution(void com.cacb.dao.BookDao.update())")private void pt(){}@Before("pt()")public void method(){System.out.println(System.currentTimeMillis());}
}

第七步、在Spring核心配置文件中开启Spring对AOP注解驱动支持

@Configuration
@ComponentScan("com.cacb")
@EnableAspectJAutoProxy
public class SpringConfig {
}

AOP工作流程

1.Spring容器启动

2.读取所有切面配置中的切入点

3.初始化Bean,判定Bean对应的类中的方法是否匹配到任意切入点

        匹配失败,则创建对象

        匹配成功,则创建原始对象(目标对象)的代理对象

4.获取Bean执行方法

        获取Bean,调用方法并执行,完成操作

        获取的Bean是代理对象时,根据代理对象的运行模式运行原始方法与增强的内容,完成操作

目标对象(Target) : 原始功能去掉共性功能对应的类产生的对象,这种对象是无法直接完成最终工作的

代理(Proxy) : 目标对象无法直接完成工作,需要对其进行功能回填,通过原始对象的代理对象实现

APO切入点表达式

切入点:要进行增强的方式

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

以上例update()方法为例,共有两种描述方式

方式一:接口方式

@Pointcut("execution(void com.cacb.dao.BookDao.update())")

方式二:实现类方式

@Pointcut("execution(void com.cacb.dao.impl.BookDaoImpl.update())")

切入点表达式标准格式:动作关键字(访问修饰符 返回值 包名.类/接口名.方法名 (参数)异常名)

动作关键字:描述切入点的行为动作,例如execution表示执行到指定切入点

访问修饰符:public,private等,可以省略

异常名:方法定义中抛出指定异常,可以省略

通配符

可以使用通配符描述切入点,快速描述

 * 单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现

execution(public * com.cacb.*.UserService.find* (*))

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

.. 多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写

execution(public User com..UserService.findById (..))

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

+ 专用于匹配子类类型

execution(* * ..*Service+.* (..))

AOP通知类型

AOP通知描述了抽取的共性功能,根据共性功能抽取的位置不同,最终运行代码时要将其加入到合理的位置

AOP通知共分为五种类型

前置通知

@Before("")

后置通知

@After("")

环绕通知

    @Around("")public void around(ProceedingJoinPoint pjp) throws Throwable{//..原方法前操作pjp.proceed(); //表述对原始操作的调用//..原方发后操作}

如果原方法有返回值 

    @Around("")public Object around(ProceedingJoinPoint pjp) throws Throwable{//..原方法前操作Object result = pjp.proceed(); //表述对原始操作的调用//..原方法后操作return result}

返回后通知

@AfterReturning("")

只有在调用方法没有抛出异常,正常运行结束后该通知才会运行 

抛出异常后通知

@AfterThrowing("")

只有在调用方法抛出异常后才会运行

@Around注意事项

1.环绕通知必须依赖形参ProceedingJoinPoint才能实现对原始方法的调用,进而实现原始方法调用前后同时添加通知

2.通知中如果未使用ProceedingJoinPoint对原始方法进行调用将跳过原始方法的执行

3.对原始方法的调用可以不接收返回值,通知方法设置成void即可,如果接收返回值,必须设定为Object类型

4.原始方法的返回值如果是void类型,通知方法的返回值类型可以设置成void,也可以设置成Object

5.由于无法预知原始方法运行后是否会抛出异常,因此环绕通知方法必须抛出Throwable对象

AOP通知获取数据

获取参数

JoinPoint:适用于前置、后置、返回后、抛出异常后通知

ProceedingJoinPoint:适用于环绕通知

获取返回值

返回后通知

环绕通知

获取异常

抛出异常后通知

 

环绕通知

相关文章:

  • Red Hat Enterprise Linux 9.3 安装图解
  • docker 使用 vcs/2018 Verdi等 eda 软件
  • python爬虫案例分享
  • 力扣每日一练(24-1-18)
  • 如何用ArcGIS制作城市用地适应性评价
  • C语言辨析——int a=5;为什么++a=1能编译通过而a++=1不行呢?
  • 在 Python 中实现语音合成的四种方法
  • js监听返回当前页面的方法
  • HCIP-BGP实验3
  • Mysql中的日志系统
  • ChatGPT与文心一言:AI助手之巅的对决
  • 利用appium自动控制移动设备并提取数据
  • 从 GPT1 - GPT4 拆解
  • 【Java】JDBC的使用
  • Yaklang 中的类型和变量
  • [数据结构]链表的实现在PHP中
  • chrome扩展demo1-小时钟
  • js 实现textarea输入字数提示
  • js继承的实现方法
  • Netty 4.1 源代码学习:线程模型
  • Stream流与Lambda表达式(三) 静态工厂类Collectors
  • 初识 webpack
  • 番外篇1:在Windows环境下安装JDK
  • 给新手的新浪微博 SDK 集成教程【一】
  • 机器人定位导航技术 激光SLAM与视觉SLAM谁更胜一筹?
  • 文本多行溢出显示...之最后一行不到行尾的解决
  • MiKTeX could not find the script engine ‘perl.exe‘ which is required to execute ‘latexmk‘.
  • ​​​​​​​GitLab 之 GitLab-Runner 安装,配置与问题汇总
  • (2)Java 简介
  • (Redis使用系列) Springboot 使用Redis+Session实现Session共享 ,简单的单点登录 五
  • (差分)胡桃爱原石
  • (初研) Sentence-embedding fine-tune notebook
  • (循环依赖问题)学习spring的第九天
  • (转)【Hibernate总结系列】使用举例
  • .naturalWidth 和naturalHeight属性,
  • .NET Core中的去虚
  • .net 开发怎么实现前后端分离_前后端分离:分离式开发和一体式发布
  • .Net 中的反射(动态创建类型实例) - Part.4(转自http://www.tracefact.net/CLR-and-Framework/Reflection-Part4.aspx)...
  • .Net+SQL Server企业应用性能优化笔记4——精确查找瓶颈
  • .pings勒索病毒的威胁:如何应对.pings勒索病毒的突袭?
  • @data注解_SpringBoot 使用WebSocket打造在线聊天室(基于注解)
  • []Telit UC864E 拨号上网
  • [1] 平面(Plane)图形的生成算法
  • [100天算法】-每个元音包含偶数次的最长子字符串(day 53)
  • [4.9福建四校联考]
  • [AI]文心一言出圈的同时,NLP处理下的ChatGPT-4.5最新资讯
  • [android] 练习PopupWindow实现对话框
  • [C#]使用DlibDotNet人脸检测人脸68特征点识别人脸5特征点识别人脸对齐人脸比对FaceMesh
  • [C#7] 1.Tuples(元组)
  • [c#基础]DataTable的Select方法
  • [C/C++]数据结构----顺序表的实现(增删查改)
  • [C++数据结构](22)哈希表与unordered_set,unordered_map实现
  • [Cocoa]iOS 开发者账户,联机调试,发布应用事宜
  • [dart学习]第四篇:函数
  • [hdu 2826] The troubles of lmy [简单计算几何 - 相似]