Spring核心—AOP

AOP

概念

  • AOP(Aspect Oriented Programing)面向切面编程,一种编程范式,隶属于软工范畴,指导开发者如何组织程序结构
  • AOP弥补了OOP的不足,基于OOP基础之上进行横向开发
    ◆ OOP规定程序开发以类为主体模型,一切围绕对象进行,完成某个任务先构建模型
    ◆ AOP程序开发主要关注基于OOP开发中的共性功能,一切围绕共性功能进行,完成某个任务先构建可能遇到的所有共性功能(当所有功能都开发出来也就没有共性与非共性之分)

作用

  • 伴随着AOP时代的降临,可以从各个行业的标准化、规范化开始入手,一步一步将所有共性功能逐一开
    发完毕,最终以功能组合来完成个别业务模块乃至整体业务系统的开发
  • 目标:将软件开发由手工制作走向半自动化/全自动化阶段,实现“插拔式组件体系结构”搭建

AOP优势

  • 提高代码的可重用性
  • 业务代码编码更简洁
  • 业务代码维护更高效
  • 业务功能扩展更便捷

AOP相关概念

  • Joinpoint(连接点):就是方法
  • Pointcut(切入点):就是挖掉共性功能的方法
  • Advice(通知):就是共性功能,最终以一个方法的形式呈现
  • Aspect(切面):就是共性功能与挖的位置的对应关系
  • Target(目标对象):就是挖掉功能的方法对应的类产生的对象,这种对象是无法直接成最终工作的
  • Weaving(织入):就是将挖掉的功能回填的动态过程
  • Proxy(代理):目标对象无法直接完成工作,需要对其进行功能回填,通过创建原始对象的代理对象实现
  • Introduction(引入/引介) :就是对原始对象无中生有的添加成员变量或成员方法

切入点表达式的组成

  • 切入点描述的是某个方法
  • 切入点表达式是一个快速匹配方法描述的通配格式,类似于正则表达式
    关键字(访问修饰符 返回值 包名.类名.方法名(参数)异常名)
    ◆ 关键字:描述表达式的匹配模式(参看关键字列表)
    ◆ 访问修饰符:方法的访问控制权限修饰符
    ◆ 类名:方法所在的类(此处可以配置接口名称)
    ◆ 异常:方法定义中指定抛出的异常
  • exp:
execution(public User com.itheima.service.UserService.findById(int))

切入点表达式——通配符

  • /* :单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现
匹配com.itheima包下的任意包中的UserService类或接口中所有find开头的带有一个参数的方法
execution(public * com.itheima.*.UserService.find*(*))
  • … :多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写
匹配com包下的任意包中的UserService类或接口中所有名称为findById的方法
execution(public User com..UserService.findById(..))
  • +:专用于匹配子类类型
execution(* *..*Service+.*(..))

切入点表达式——逻辑运算符

  • && :连接两个切入点表达式,表示两个切入点表达式同时成立的匹配
  • || :连接两个切入点表达式,表示两个切入点表达式成立任意一个的匹配
  • ! :连接单个切入点表达式,表示该切入点表达式不成立的匹配

AOP的通知类型

  • 前置通知:原始方法执行前执行,如果通知中抛出异常,阻止原始方法运行,一般应用于数据校验
    ⚫ 名称:aop:before
    ⚫ 类型:标签
    ⚫ 归属:aop:aspect标签
    ⚫ 作用:设置前置通知
    ⚫ 说明:一个aop:aspect标签中可以配置多个aop:before标签
    ⚫ 基本属性:
    ◆ method :在通知类中设置当前通知类别对应的方法
    ◆ pointcut :设置当前通知对应的切入点表达式,与pointcut-ref属性冲突
    ◆ pointcut-ref :设置当前通知对应的切入点id,与pointcut属性冲突
    ⚫ 格式:
<aop:aspect ref="adviceId">
<aop:before method="methodName" pointcut="……"/>
</aop:aspect>
  • 后置通知:原始方法执行后执行,无论原始方法中是否出现异常,都将执行通知;一般应用于现场清理
    ⚫ 名称:aop:after
    ⚫ 类型:标签
    ⚫ 归属:aop:aspect标签
    ⚫ 作用:设置后置通知
    ⚫ 说明:一个aop:aspect标签中可以配置多个aop:after标签
    ⚫ 基本属性:
    ◆ method :在通知类中设置当前通知类别对应的方法
    ◆ pointcut :设置当前通知对应的切入点表达式,与pointcut-ref属性冲突
    ◆ pointcut-ref :设置当前通知对应的切入点id,与pointcut属性冲突
    ⚫ 格式:
<aop:aspect ref="adviceId">
<aop:after method="methodName" pointcut="……"/>
</aop:aspect>
  • 返回后通知:原始方法正常执行完毕并返回结果后执行,如果原始方法中抛出异常,无法执行;一般应用于返回值相关数据处理
    ⚫ 名称:aop:after-returning
    ⚫ 类型:标签
    ⚫ 归属:aop:aspect标签
    ⚫ 作用:设置返回后通知
    ⚫ 说明:一个aop:aspect标签中可以配置多个aop:after-returning标签
    ⚫ 基本属性:
    ◆ method :在通知类中设置当前通知类别对应的方法
    ◆ pointcut :设置当前通知对应的切入点表达式,与pointcut-ref属性冲突
    ◆ pointcut-ref :设置当前通知对应的切入点id,与pointcut属性冲突
    ⚫ 格式:
<aop:aspect ref="adviceId">
<aop:after-returning method="methodName" pointcut="……"/>
</aop:aspect>
  • 抛出异常后通知:原始方法抛出异常后执行,如果原始方法没有抛出异常,无法执行;一般应用于对原始方法中出现的异常信息进行处理
    ⚫ 名称:aop:after-throwing
    ⚫ 类型:标签
    ⚫ 归属:aop:aspect标签
    ⚫ 作用:设置抛出异常后通知
    ⚫ 说明:一个aop:aspect标签中可以配置多个aop:after-throwing标签
    ⚫ 基本属性:
    ◆ method :在通知类中设置当前通知类别对应的方法
    ◆ pointcut :设置当前通知对应的切入点表达式,与pointcut-ref属性冲突
    ◆ pointcut-ref :设置当前通知对应的切入点id,与pointcut属性冲突
    ⚫ 格式:
<aop:aspect ref="adviceId">
<aop:after-throwing method="methodName" pointcut="……"/>
</aop:aspect>
  • 环绕通知:在原始方法执行前后均有对应执行执行,还可以阻止原始方法的执行;一般应用于十分强大,可以做任何事情
    ⚫ 名称:aop:around
    ⚫ 类型:标签
    ⚫ 归属:aop:aspect标签
    ⚫ 作用:设置环绕通知
    ⚫ 说明:一个aop:aspect标签中可以配置多个aop:around标签
    ⚫ 基本属性:
    ◆ method :在通知类中设置当前通知类别对应的方法
    ◆ pointcut :设置当前通知对应的切入点表达式,与pointcut-ref属性冲突
    ◆ pointcut-ref :设置当前通知对应的切入点id,与pointcut属性冲突
    ⚫ 格式:
<aop:aspect ref="adviceId">
<aop:around method="methodName" pointcut="……"/>
</aop:aspect>

环绕通知开发方式

  • 环绕通知是在原始方法的前后添加功能,在环绕通知中,存在对原始方法的显式调用
public Object around(ProceedingJoinPoint pjp) throws Throwable {
Object ret = pjp.proceed();
return ret;
}
  • 环绕通知方法相关说明:
    ◆ 方法须设定Object类型的返回值,否则会拦截原始方法的返回。如果原始方法返回值类型为
    void,通知方法也可以设定返回值类型为void,最终返回null
    ◆ 方法需在第一个参数位置设定ProceedingJoinPoint对象,通过该对象调用proceed()方法,实
    现对原始方法的调用。如省略该参数,原始方法将无法执行
    ◆ 使用proceed()方法调用原始方法时,因无法预知原始方法运行过程中是否会出现异常,强制抛
    出Throwable对象,封装原始方法中可能出现的异常信息

当同一个切入点配置了多个通知时,通知会存在运行的先后顺序,该顺序以通知配置的顺序为准

AOP开发过程

  • 开发阶段(开发者完成)
    ◆ 正常的制作程序
    ◆ 将非共性功能开发到对应的目标对象类中,并制作成切入点方法
    ◆ 将共性功能独立开发出来,制作成通知
    ◆ 在配置文件中,声明切入点
    ◆ 在配置文件中,声明切入点与通知间的关系(含通知类型),即切面
  • 运行阶段(AOP完成)
    ◆ Spring容器加载配置文件,监控所有配置的切入点方法的执行
    ◆ 当监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置将通知对应的功能织入,完成完整的代码逻辑并运行

通知获取参数数据
在这里插入图片描述

通知获取返回值数据

在这里插入图片描述
在这里插入图片描述

通知获取异常数据
在这里插入图片描述
在这里插入图片描述

AOP配置

  • XML配置
    ⚫ 名称:aop:config
    ⚫ 类型:标签
    ⚫ 归属:beans标签
    ⚫ 作用:设置AOP
    ⚫ 说明:一个beans标签中可以配置多个aop:config标签
    ⚫ 格式:
<beans>
<aop:config>……</aop:config>
<aop:config>……</aop:config>
</beans>
◆名称:aop:aspect
◆ 类型:标签
◆ 归属:aop:config标签
◆作用:设置具体的AOP通知对应的切入点
◆ 说明:一个aop:config标签中可以配置多个aop:aspect标签
◆ 基本属性:ref :通知所在的bean的id
◆ 格式:
<aop:config>
<aop:aspect ref="beanId">……</aop:aspect>
<aop:aspect ref="beanId">……</aop:aspect>
</aop:config>
⚫ 名称:aop:pointcut
⚫ 类型:标签
⚫ 归属:aop:config标签、aop:aspect标签
⚫ 作用:设置切入点
⚫ 说明:一个aop:config标签中可以配置多个aop:pointcut标签,且该标签可以配置在aop:aspect标签内
⚫ 基本属性:
	◆ id :识别切入点的名称
	◆ expression :切入点表达式
⚫ 格式:
<aop:config>
<aop:pointcut id="pointcutId" expression="……"/>
<aop:aspect>
<aop:pointcut id="pointcutId" expression="……"/>
</aop:aspect>
</aop:config>

注解开发AOP制作步骤

  • 在XML格式基础上
    ◆ 导入坐标(伴随spring-context坐标导入已经依赖导入完成)
    ◆ 开启AOP注解支持
    ◆ 配置切面@Aspect
    ◆ 定义专用的切入点方法,并配置切入点@Pointcut
    ◆ 为通知方法配置通知类型及对应切入点@Before

  • 注意事项

    1. 切入点最终体现为一个方法,无参无返回值,无实际方法体内容,但不能是抽象方法
    2. 引用切入点时必须使用方法调用名称,方法后面的()不能省略
    3. 切面类中定义的切入点只能在当前类中使用,如果想引用其他类中定义的切入点使用“类名.方法名()”引用
    4. 可以在通知类型注解后添加参数,实现XML配置中的属性,例如after-returning后的returning属性
      在这里插入图片描述
  • @Aspect
    ⚫ 类型:注解
    ⚫ 位置:类定义上方
    ⚫ 作用:设置当前类为切面类
    ⚫ 说明:一个beans标签中可以配置多个aop:config标签
    ⚫ 格式:

@Aspect
public class AopAdvice {
}
  • @Pointcut
    ⚫ 类型:注解
    ⚫ 位置:方法定义上方
    ⚫ 作用:使用当前方法名作为切入点引用名称
    ⚫ 说明:被修饰的方法忽略其业务功能,格式设定为无参无返回值的方法,方法体内空实现(非抽象)
    ⚫ 格式:
@Pointcut("execution(* *(..))")
public void pt() {
}
  • @Before
    ⚫类型:注解
    ⚫ 位置:方法定义上方
    ⚫ 作用:标注当前方法作为前置通知
    ⚫ 格式:
@Before("pt()")
public void before(){
}
  • @After
    ⚫ 类型:注解
    ⚫ 位置:方法定义上方
    ⚫ 作用:标注当前方法作为后置通知
    ⚫ 格式:
@After("pt()")
public void after(){
}
  • @AfterReturning
    ⚫ 类型:注解
    ⚫ 位置:方法定义上方
    ⚫ 作用:标注当前方法作为返回后通知
    ⚫ 特殊参数:
    ◆ returning :设定使用通知方法参数接收返回值的变量名
    ⚫ 格式:
@AfterReturning(value="pt()",returning = "ret")
public void afterReturning(Object ret) {
}
  • @AfterThrowing
    ⚫ 类型:注解
    ⚫ 位置:方法定义上方
    ⚫ 作用:标注当前方法作为异常后通知
    ⚫ 特殊参数:
    ◆ throwing :设定使用通知方法参数接收原始方法中抛出的异常对象名
    ⚫ 格式:
@AfterThrowing(value="pt()",throwing = "t")
public void afterThrowing(Throwable t){
}
  • @Around
    ⚫ 类型:注解
    ⚫ 位置:方法定义上方
    ⚫ 作用:标注当前方法作为环绕通知
    ⚫ 格式:
@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
Object ret = pjp.proceed();
return ret;
}

AOP注解驱动

⚫ 名称:@EnableAspectJAutoProxy
⚫ 类型:注解
⚫ 位置:Spring注解配置类定义上方
⚫ 作用:设置当前类开启AOP注解驱动的支持,加载AOP注解
⚫ 格式:
@Configuration
@ComponentScan("com.itheima")
@EnableAspectJAutoProxy
public class SpringConfig {
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值