Spring AOP——简单粗暴,小白教学
阅读原文时间:2021年04月20日阅读:1

1.Spring AOP是什么?

Aspect Oriented Programming:面向切面编程
什么时候会出现面向切面编程的需求?按照软件重构的思想,如果多个类中出现重复的代码,就应该考虑定义一个共同的抽象类,将这些共同的代码提取到抽象类中,比如Teacher,Student都有username,那么就可以把username及相关的get、set方法抽取到SysUser中,这种情况,我们称为纵向抽取。
但是如果,我们的情况是以下情况,又该怎么办? 给所有的类方法添加性能检测,事务控制,该怎么抽取? PerformanceMonitor TransactionManager AOP就是希望将这些分散在各个业务逻辑代码中的相同代码,通过横向切割的方式抽取到一个独立的模块中,让业务逻辑类依然保存最初的单纯。

抽取出来简单,难点就是如何将这些独立的逻辑融合到业务逻辑中,完成跟原来一样的业务逻辑,这就是AOP解决的主要问题。

还是看不懂?接下基础案例说明

1.1 基础案例说明

为了更好说明,我们接下来,要讲解的知识点,我们以一个常见的例子来说明
我们以数据库的操作为例来说明:

  1. 获取连接对象
  2. 执行SQL(核心业务代码)
  3. 如果有异常,回滚事务,无异常则提交事务
  4. 关闭连接

上述的几个部署,“2”是核心业务代码,其他都是非核心业务代码,但是我们又必须写 而面向切面编程就是为了解决这样的问题,将这些非核心业务代码进行抽离,这样开发者只需要关注“核心业务代码”即可。 这样开发效率自然提高。

在项目开发中,SpringAOP是非常常用的技能之一,下面我画一个图来说明,spring都做了什么

2. AOP术语

  • 连接点(Joinpoint) 程序执行的某个特定位置,如某个方法调用前,调用后,方法抛出异常后,这些代码中的特定点称为连接点。简单来说,就是在哪加入你的逻辑增强
    连接点表示具体要拦截的方法,上面切点是定义一个范围,而连接点是具体到某个方法
  • 切点(PointCut) 每个程序的连接点有多个,如何定位到某个感兴趣的连接点,就需要通过切点来定位。比如,连接点--数据库的记录,切点--查询条件
    切点用于来限定Spring-AOP启动的范围,通常我们采用表达式的方式来设置,所以关键词是范围
  • 增强(Advice) 增强是织入到目标类连接点上的一段程序代码。在Spring中,像BeforeAdvice等还带有方位信息
    通知是直译过来的结果,我个人感觉叫做“业务增强”更合适 对照代码就是拦截器定义的相关方法,通知分为如下几种:
    前置通知(before):在执行业务代码前做些操作,比如获取连接对象
    后置通知(after):在执行业务代码后做些操作,无论是否发生异常,它都会执行,比如关闭连接对象
    异常通知(afterThrowing):在执行业务代码后出现异常,需要做的操作,比如回滚事务
    返回通知(afterReturning),在执行业务代码后无异常,会执行的操作
    环绕通知(around),这个目前跟我们谈论的事务没有对应的操作,所以暂时不谈
  • 目标对象(Target) 需要被加强的业务对象
  • 织入(Weaving) 织入就是将增强添加到对目标类具体连接点上的过程。
    织入是一个形象的说法,具体来说,就是生成代理对象并将切面内容融入到业务流程的过程。
  • 代理类(Proxy) 一个类被AOP织入增强后,就产生了一个代理类。
  • 切面(Aspect) 切面由切点和增强组成,它既包括了横切逻辑的定义,也包括了连接点的定义,SpringAOP就是将切面所定义的横切逻辑织入到切面所制定的连接点中。
    比如上文讨论的数据库事务,这个数据库事务代码贯穿了我们的整个代码,我们就可以这个叫做切面。 SpringAOP将切面定义的内容织入到我们的代码中,从而实现前后的控制逻辑。 比如我们常写的拦截器Interceptor,这就是一个切面类

2.1 一图胜千言

3. Spring概述

1,AOP编程可不是Spring独有的,Spring只是支持AOP编程的框架之一,这一点非常重要,切勿搞反了关系。
2,AOP分两类,一类可以对方法的参数进行拦截,一类是对方法进行拦截,SpringAOP属于后者,所以Spring的AOP是属于方法级的

4. Spring AOP实现-基于注解的方式

@Asoect创建切面类

@Before: 标识一个前置增强方法,相当于BeforeAdvice的功能.
@After: final增强,不管是抛出异常或者正常退出都会执行.
@AfterReturning: 后置增强,似于AfterReturningAdvice, 方法正常退出时执行.
@AfterThrowing: 异常抛出增强,相当于ThrowsAdvice.
@Around: 环绕增强,相当于MethodInterceptor.
execution:用于匹配方法执行的连接点;

eg.

  • 任意公共方法的执行:execution(public * *(..))
  • 任何一个以“set”开始的方法的执行:execution(* set*(..))
  • AccountService 接口的任意方法的执行:execution(* com.xyz.service.AccountService.*(..))
  • 定义在service包里的任意方法的执行: execution(* com.xyz.service.*.*(..))
  • 定义在service包和所有子包里的任意类的任意方法的执行:execution(* com.xyz.service..*.*(..))

第一个表示匹配任意的方法返回值, …(两个点)表示零个或多个,第一个…表示service包及其子包,第二个表示所有类, 第三个*表示所有方法,第二个…表示方法的任意参数个数

  • 定义在pointcutexp包和所有子包里的JoinPointObjP2类的任意方法的执行:execution(*com.test.spring.aop.pointcutexp..JoinPointObjP2.*(..))")

  • pointcutexp包里的任意类: within(com.test.spring.aop.pointcutexp.*)

  • pointcutexp包和所有子包里的任意类:within(com.test.spring.aop.pointcutexp..*)

  • 实现了Intf接口的所有类,如果Intf不是接口,限定Intf单个类:this(com.test.spring.aop.pointcutexp.Intf)

  • 当一个实现了接口的类被AOP的时候,用getBean方法必须cast为接口类型,不能为该类的类型

  • 带有@Transactional标注的所有类的任意方法: @within(org.springframework.transaction.annotation.Transactional) @target(org.springframework.transaction.annotation.Transactional)

  • 带有@Transactional标注的任意方法:
    @annotation(org.springframework.transaction.annotation.Transactional)
    @within和@target针对类的注解,@annotation是针对方法的注解

  • 参数带有@Transactional标注的方法:@args(org.springframework.transaction.annotation.Transactional)

  • 参数为String类型(运行是决定)的方法: args(String)

    至于@Around解析请跳转:

  • https://blog.csdn.net/qq_41981107/article/details/85260765

    参考博客:

    https://my.oschina.net/itblog/blog/211693

    https://my.oschina.net/u/3434392/blog/1625493