一、AOP入门简介

AOP(Aspect Oriented Programming)面向切面编程,是一种编程范式,可以知道开发者如何组织程序结构

作用:在不惊动原始设计的基础上为其进行功能增强。(无侵入式编程)

AOP的核心概念:

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

    • 在SpringAOP中可以理解为方法的执行。
  • 切入点(PointCut):匹配连接点的式子
    • 在SpringAOP中,一个切入点只可以描述 一个具体的方法,也可以匹配多个方法。

      • 一个具体方法:com.huawei.dao包下的BookDao接口中的无形参无返回值的save方法。
      • 匹配多个方法:所有的save方法,所有的get开头的方法,所有以Dao结尾的接口中的任意方法,所有带有一个参数的方法。
  • 通知(Advice):在切入点处执行的操作,也就是共性功能。
    • 在SpringAOP中,功能最终会以 方法的形式呈现出来。
  • 通知类:定义通知的类。
  • 切面(Aspect):描述通知与切入点的对应关系。

连接点代表所有的方法,切入点代表要追加功能的方法,在范围上连接点是包含切入点的。

二、AOP工作流程

1、Spring容器启动

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

3、初始化bean,判断bean对应的类中的方法是否匹配到任意切入点

  • 匹配失败、创建对象
  • 匹配成功,创建原始对象(目标对象)的代理对象

4、获取bea执行方法

  • 获取bean,调用方法并执行,完成操作
  • 获取到的bean是代理对象的时候,根据代理对象的运行模式运行原始方法与增强的内容来完成操作

AOP的核心概念

  • 目标对象(Target):原始功能去掉共性功能对应的类产生的对象,这种对象是无法直接完成最终工作的;
  • 代理(Proxy):目标对象无法直接完成工作,需要对其进行功能回填,通过原始对象的代理对象实现。

三、AOP切入点表达式

切入点:要增强的方法

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

描述方式一:执行com.huawei.dao包下的BookDao接口中的无参数update方法

execution(void com.huawei.dao.BookDao.update())

描述方式二:执行com.huawei.dao.impl包下的BookDaoImpl类中的无参数update方法

execution(void com.huawei.dao.impl.BookDaoImpl.update())

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

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

  • *:单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现
execution(public * com.huawei.*.UserService.find*(*))
  • ..:多个连续的任意符号,可以独立出现,常用于简化包名和参数的书写
execution(public User com..UserService.findById(..))
  • +:专用于匹配子类的类型
execution(* *..*Service+.*(..))

书写技巧

  • 所有代码按照规范标准开发,否则以下的这些技巧会全部失效
  • 描述切入点通常描述接口,而不去描述实现类
  • 访问修饰符对接口开发均采用public描述(可以省略访问控制修饰符描述
  • 返回值类型对于增删改类使用精准类型加速匹配,对于查询类使用*通配快速描述
  • 包名书写尽量不要使用..来匹配,效率过低,通常用*来做单个包的描述匹配,或者精准匹配
  • 接口名/类名书写名称与模块相关的采用*匹配,例如UserService书写成*Service,绑定业务接口名
  • 方法名书写应该以动词进行精确匹配,名词采用*匹配,例如getById书写成getBy*,selectAll写成selectAll
  • 参数规则较为复杂,根据业务方法灵活调整
  • 通常不使用异常作为匹配规则

四、AOP通知类型

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

AOP通知可以分为5种类型:

  • 前置通知
  • 后置通知
  • 环绕通知(重点)
  • 返回后通知(了解)
  • 抛出异常后通知(了解)

4.1 前置通知

@Before("pt()")
public void before() {
System.out.println("before advice...");
}

4.2 后置通知

@After("pt()")
public void after() {
System.out.println("after advice...");
}

4.3 环绕通知(重点)

@Around("pt()")
public void around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("around before advice..."); // 表示对原始程序的调用
pjp.proceed(); System.out.println("around after advice...");
}

如果我们采取环绕通知的原函数是有返回值的,那么我们也需要采取对应的写法完善这部分内容:

@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注意事项:

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

2、通知中如果未使用ProceedingJoinPoing对原始方法进行调用的话就会直接跳过原始方法的执行。

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

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

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

4.4 返回后通知

与正常的后置通知的区别是,返回后通知只有在源程序没有抛出异常,正常结束的情况下才会使用。(了解即可,实际并不常用)

4.5 抛出异常后通知

只有在源程序抛出异常的情况下才会被调用,如果源程序正常结束而没有抛出任何异常的话,则不会被调用。

五、AOP通知获取数据

  • 获取切入点方法的参数

    • JoinPoint:适用于前置、后置、返回后、抛出异常后通知
    • ProceedJointPoint:适用于环绕通知
  • 获取切入点方法的返回值
    • 返回后通知
    • 环绕通知
  • 获取切入点方法的运行异常信息
    • 抛出异常后通知
    • 环绕通知

5.1 对于参数的获取

前置后置方法获取函数参数的demo:

@Before("pt()")
public void before(JoinPoint pj) {
Object[] args = pj.getArgs();
system.out.println(Arrays.toString(args)); System.out.println("before dao ...");
}

环绕通知方法可以拿到参数之后进行一系列处理再传入,具体实现如下:

@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
Object[] args = pjp.getArgs();
System.out.println(Arrays.toString(args)); // 可以在此处对数据进行清洗或者进一步操作
args[0] == 666; Object ret = pjp.proceed(args); // 此时就是使用我们新传入的参数进行相关的业务操作了
return ret;
}

5.2 对于返回值的获取

采用环绕通知获取返回值的方法上面已经展示了,因此此处不再赘述。

返回后通知demo:

@AfterReturning(value="pt()", returning="ret")		// 此处returning属性就是代表接收返回值的
public void afterReturning(Object ret) {
System.out.println("afterReturning result is : " + ret);
}

需要注意的是,如果afterReturning方法中需要连接点的话,参数位置必须是第一个,也可以直接省略不写,public void afterReturning(JoinPoint jp, Object ret)

5.3 对于异常的获取

环绕通知中只需要使用try-catch块包围即可,之后我们可以在catch中对捕获到的异常做出对应的操作。

抛出异常后通知demo:

@AfterThrowing(value="pt()", throwing="t")
public void afterThrowing(Throwable t) {
System.out.println("afterThrowing dao ...");
}

六、案例及总结

6.1 案例

需求:对百度网盘分享链接输入密码时尾部多输入的空格进行兼容性处理

分析

  • 在业务方法执行之前对所有的输入参数进行格式处理
  • 适用处理后的参数再去调用原始方法 —— 环绕通知中存在对原始方法的调用

核心实现代码:

@Around("servicePt()")
public Object trimStr(ProceedingJoinPoint pjp) throw Throwable {
Object[] args = pjp.getArgs(); // 循环判断是否需要去除空格
for (int i = 0; i < args.length; i++) {
// 如果判定当前参数是字符串的话,则执行去空格操作
if (args[i].getClass.equals(String.getClass())) {
args[i] = args[i].toSrting().trim();
}
} Object ret = pjp.proceed(args);
return ret;
}

6.2 AOP学习总结

在AOP的实际实现中,我们比较常用的是环绕通知:

  • 环绕通知依赖形参ProceedingJoinPoint才能够实现对原始方法的调用
  • 环绕通知可以隔离原始方法的调用执行
  • 环绕通知的返回值设置为Object类型
  • 环绕通知可以对原始方法调用过程中出现的异常进行处理。

SSM框架学习-AOP学习笔记的更多相关文章

  1. SSM框架—Spring AOP之基于注解的声明式AspectJ(Demo)

    项目结构 XML <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http ...

  2. SSM框架之AOP、动态代理、事务处理相关随笔

    AOP: 原理:底层利用动态代理(两种动态代理技术都使用了) 两种实现方案: 第一种:JDK动态代理技术 实现的InvocationHandler接口,要想实现某个类的动态代理对象,必须有接口有实现类 ...

  3. Java基础及JavaWEB以及SSM框架学习笔记Xmind版

    Java基础及JavaWEB以及SSM框架学习笔记Xmind版 转行做程序员也1年多了,最近开始整理以前学习过程中记录的笔记,以及一些容易犯错的内容.现在分享给网友们.笔记共三部分. JavaSE 目 ...

  4. SSM框架学习之高并发秒杀业务--笔记2-- DAO层

    上节中利用Maven创建了项目,并导入了所有的依赖,这节来进行DAO层的设计与开发 第一步,创建数据库和表. 首先分析业务,这个SSM匡济整合案例是做一个商品的秒杀系统,要存储的有:1.待秒杀的商品的 ...

  5. IDEA 整合 SSM 框架学习

    认识 Spring 框架 更多详情请点击这里:这里 Spring 框架是 Java 应用最广的框架,它的成功来源于理念,而不是技术本身,它的理念包括 IoC (Inversion of Control ...

  6. Spring MVC 学习总结(十一)——IDEA+Maven+多模块实现SSM框架集成

    一.SSM概要 与SSH(Struts/Spring/Hibernate/)一样,Spring+SpringMVC+MyBatis也有一个简称SSM,Spring实现业务对象管理,Spring MVC ...

  7. Spring入门IOC和AOP学习笔记

    Spring入门IOC和AOP学习笔记 概述 Spring框架的核心有两个: Spring容器作为超级大工厂,负责管理.创建所有的Java对象,这些Java对象被称为Bean. Spring容器管理容 ...

  8. AOP学习笔记一

    软件开发的目的是为了解决各种需求,包括业务需求和系统需求.目前,业界通过使用面向对象的编程思想,已经可以对业务需求等普通关注点进行很好的抽象与封装,并且使之模块化.但是对于系统需求一类的关注点来说,情 ...

  9. Aop学习笔记

    在学习编程这段时间我想大家都是习惯了面向过程或者面向对象的思想来编程,较少或者没有接触过面向方面编程的思想. 那么什么是面向方面(Aspect)——其实就是与核心业务处理逻辑无关的切面,例如记录日志. ...

  10. SSM框架学习思维导图

    SSM框架学习思维导图 2017年08月11日 20:17:28 阅读数:1141 放上前段时间学习SSM框架以及Spring.SpringMVC.MyBatis的学习结果,输出思维导图一共四幅图.这 ...

随机推荐

  1. 跨机房ES同步实战

    作者:谢泽华 背景 众所周知单个机房在出现不可抗拒的问题(如断电.断网等因素)时,会导致无法正常提供服务,会对业务造成潜在的损失.所以在协同办公领域,一种可以基于同城或异地多活机制的高可用设计,在保障 ...

  2. UIAutomator测试框架介绍

    uiautomator简介 UiAutomator是Google提供的用来做安卓自动化测试的一个Java库,基于Accessibility服务.功能很强,可以对第三方App进行测试,获取屏幕上任意一个 ...

  3. 从0到1学Python丨图像平滑方法的两种非线性滤波:中值滤波、双边滤波

    摘要:常用于消除噪声的图像平滑方法包括三种线性滤波(均值滤波.方框滤波.高斯滤波)和两种非线性滤波(中值滤波.双边滤波),本文将详细讲解两种非线性滤波方法. 本文分享自华为云社区<[Python ...

  4. 关于ckPlayer 视频加密那些事

    最近疫情期间,公司在做一个在线行业教育收费平台,所以不得不做视频转码/切片/加密. 现在只说视频加密如何实现,找遍了所有百度,几乎没有提供相应的源码和例子. 而ckPlayer官网有一个收费的案例:如 ...

  5. [攻防世界][江苏工匠杯]unseping

    打开靶机对应的url 上来就是代码审计 <?php highlight_file(__FILE__); class ease{ private $method; private $args; f ...

  6. json 提取器将提取的所有id拼接成字符串

    1.添加json提取器,提取所有的id 2.添加调试后置处理器查看buildid_ALL值以及类型 当需要将提取的id拼接成字符串时,此时使用json提取器并勾选Compute concatenati ...

  7. Jmeter 之bzm- Concurrency Thread Group 压测

    bzm- Concurrency Thread Group  并发线程组代替 jp@gc - Stepping Thread Group线程组. 1.  下载jmeter-plugins-manage ...

  8. Hadoop详解(02)Hadoop集群运行环境搭建

    Hadoop详解(02)Hadoop集群运行环境搭建 虚拟机环境准备 虚拟机节点数:3台 操作系统版本:CentOS-7.6-x86-1810 虚拟机 内存4G,硬盘99G IP地址分配 192.16 ...

  9. A. Greatest Convex【Codeforces Round #842 (Div. 2)】

    A. Greatest Convex You are given an integer \(k\). Find the largest integer \(x\), where \(1≤x<k\ ...

  10. Redis哨兵集群搭建-Docker-Compose

    title: Redis哨兵集群搭建(Docker-Compose) date: 2022-09-27 17:00:56 tags: - Redis 代码地址:https://github.com/l ...