一、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. uni 结合vuex 编写动态全局配置变量 this.baseurl

    在日常开发过程,相信大家有遇到过各种需求,而我,在这段事件便遇到了一个,需要通过用户界面配置动态接口,同时,因为是app小程序开发,所以接口中涉及到了http以及websocket两个类型的接口. 同 ...

  2. instanceof和Class.isAssignableFrom的区别

    1. Class.isAssignableFrom 偶然看见同事写的一段代码是这样的 if( AfterRender.class.isAssignableFrom( assembly.getClass ...

  3. 回溯法求解n皇后问题(复习)

    回溯法 回溯法是最常用的解题方法,有"通用的解题法"之称.当要解决的问题有若干可行解时,则可以在包含问题所有解的空间树中,按深度优先的策略,从根节点出发搜索解空间树.算法搜索至解空 ...

  4. Python报SyntaxError: Missing parentheses in call to ‘print’. Did you mean print()

    SyntaxError: Missing parentheses in call to 'print'. Did you mean print()原因:python2.X版本与python3.X版本输 ...

  5. C# 正则表达式常用的符号和模式解析

    〇.正则表达式的基本语法符号 若只简单匹配固定字符串,则无需任何修饰符,例如:需要匹配字符串 77,则可直接写:new Regex("77"). 下边例举一下常用的符号:(知道下面 ...

  6. [WPF]限制程序单例运行

    代码 System.Threading.Mutex mutex; protected override void OnStartup(StartupEventArgs e) { bool ret; m ...

  7. mongdb遭遇勒索,用备份进行数据恢复

    mongdb遭遇勒索,用备份进行数据恢复 1.背景: 某台MongoDB服务器,没有配置用户名密码,放到公网不到一天,遭到删库勒索 All your data is a backed up. You ...

  8. 字符编码,存储引擎及MySQL字段类型相关知识点

    字符编码,存储引擎及MySQL字段类型相关知识点 一.字符编码 1.在终端输入\s,查看数据库的基本信息(当前用户,版本,编码,端口号) 2.默认的配置文件是my-default.ini 拷贝上述的文 ...

  9. 【分析笔记】全志 i2c-sunxi.c 控制器驱动分析

    分析平台:全志 A64 内核版本:Linux 4.9 数据手册:Allwinner_A64_User_Manual_V1.1.pdf (whycan.com) 驱动框架 I2C 设备驱动 作为方案应用 ...

  10. 【分析笔记】全志平台 gpio_wdt 驱动应用和 stack crash 解决

    使用说明 第一次遇到看门狗芯片是通过切换电平信号来喂狗,如 SGM706 芯片,之前也比较少会用到看门狗芯片.原本打算参考 sunxi-wdt.c 的框架,利用定时器自己写一个,无意中发现内核已经有 ...