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

SpringAop的快速入门

SpringAop的快速入门

AOP

AOP:Aspect Oriented Programming(面向切面编程),是一种编程范式,将通用功能(如日志、事务、权限)从核心业务逻辑中剥离,用于实现“横向切割”的代码复用。 此外AOP对原有代码是没有任何侵入性的,不需要修改任何的业务代码。

AOP的核心概念

  • **连接点(JoinPoint):**连接点指的是可以被aop控制的方法。

  • **通知(Advice):**对重复逻辑抽取形成的通用方法简称为通知。

  • **切入点(PointCut):**匹配特定条件的连接点,通知仅会在切入点方法执行时被应用;切入点就是实际被aop控制的方法。

  • 切面:Aspect,描述通知与切入点的对应关系,简单来说切面就是通知+切入点的组合,而切面所在的类我们常称之为切面类。

  • 目标对象:Target,通知所作用的对象被称之为目标对象。

SpringAop的快速入门

SpringAOP是Spring框架中对AOP思想的实现。

1). 引入相关依赖

<!-- 引入SpringAop相关依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2). 编写AOP切面类

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;@Slf4j
@Component
@Aspect//标识这是一个切面类
public class DemoAspect {//前置通知@Before("execution(* com.ryuki.springaopquickstart.service.imp.*.say*(..))")public void before() {log.info(" before... ");}//环绕通知@Around("execution(* com.ryuki.springaopquickstart.service.imp.*.say*(..))")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {log.info(" around... before ... ");//SpringAop会将连接点信息都封装到joinPoint中,通过jointPoint调用目标对象的原始方法执行Object result = joinPoint.proceed();log.info(" around... after ... ");return result;}//目标方法正确返回后通知@AfterReturning("execution(* com.ryuki.springaopquickstart.service.imp.*.say*(..))")public void afterReturning() {log.info(" afterReturning... ");}//目标方法抛出异常后通知@AfterThrowing("execution(* com.ryuki.springaopquickstart.service.imp.*.say*(..))")public void afterThrowing() {log.info(" afterThrowing... ");}//后置通知@After("execution(* com.ryuki.springaopquickstart.service.imp.*.say*(..))")public void after() {log.info(" after... ");}}

在切面类上添加@Aspect注解标识这是一个切面类,同时将给切面类交由IOC容器管理,只有交由IOC管理这个切面类才能够生效。

启动服务器,访问相关资源查看控制台日志信息如下:

  • 程序正常执行情况下:目标方法执行前后插入对应通知中的逻辑。

在这里插入图片描述

  • 程序异常运行:

在这里插入图片描述

aop核心概念的再认识
  • 连接点(JointPoint):

在这里插入图片描述

  • 切入点(PointCut):

在这里插入图片描述

  • 通知(Advice):

在这里插入图片描述

  • 切面(Aspect):

在这里插入图片描述

通知类型

在通知方法前加上相应的注解指定通知类型:

通知类型解释
@Around环绕通知,此注解标注的通知方法在目标方法前、后都被执行
@Before前置通知,此注解标注的通知方法在目标方法前被执行
@After后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常抛出
@AfterReturning目标方法正确返回后通知,出现异常不会执行
@AfterThrowing目标方法抛出异常后通知,只有目标方法抛出异常才会之执行

观察上面程序控制台输出日志,我们可以发现通知类型的不同控制着执行时机的不同,同时@AfterReturning 和@AfterThrowing这两个注解是互斥的,不会同时执行。

注意:

SpringAop会将对应的连接点信息封装到ProceedingJoinPoint中,且@Around环绕通知会在目标方法执行前后执行。

因此@Around环绕通知需要自己调用 ProceedingJoinPoint类提供的proceed() 来让原始方法执行且环绕通知方法必须指定返回值类型为Object来接受原始方法的返回值

切入点表达式

描述切入点方法的表达式叫做切入点表达式,切入点表达式是用来决定SpringAOP实际控制那些方法。

  • 常见的形式:

    1. @annotation(……) :基于注解匹配切入点

    在这里插入图片描述

    1. execution(…):根据方法签名匹配切入点

    在这里插入图片描述

@annotation(…)
@Component
@Aspect
@Slf4j
public class Aspect1 {@Before("@annotation(com.ryuki.springaopquickstart.anno.Operation)")public void before() {log.info("annotation.....before... ");}@After("@annotation(com.ryuki.springaopquickstart.anno.Operation)")public void after() {log.info("annotation....after... ");}
}

在这里插入图片描述

execution(…)

execution主要根据方法的返回值、包名、类名、方法名、方法参数等信息来匹配,语法如下:

execution([访问修饰符]  返回值  [包名.类名.]方法名(方法参数) [throws 异常?])

特别说明:带[]的部分可省略不写

我们可以配合通配符来描述切入点:

  • *匹配单个独立的任意符号,可以通配任意返回值、包名、类名、方法名、任意类型的一个参数,也可以通配包、类、方法名的一部分
  • ..匹配多个连续的任意符号,可以通配任意层级的包,或任意类型、任意个数的参数
@Component
@Aspect
@Slf4j
public class Aspect2 {@Before("execution(public String com.ryuki.springaopquickstart.service.imp.*.*(..))")public void before() {log.info("execution.....before... ");}@After("execution(* com.ryuki.springaopquickstart.service.imp.*.*(..))")public void after() {log.info("execution....after... ");}
}

在这里插入图片描述

前面编写的AOP入门切面类中,每一个注解的切点表达式都相同,此时我们可以通过@PointCut注解将共性的切点表达式抽取出来;定义一个切入点方法,在该方法上通过@PointCut注解抽取公共的切点表达式,需要时直接引入即可:

package com.ryuki.springaopquickstart.aspect;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;@Slf4j
@Component
@Aspect
public class DemoAspect {//切入点方法@Pointcut("execution(* com.ryuki.springaopquickstart.service.imp.*.*(..))")public void pointcut() {}//后续直接引入该切入点即可//前置通知@Before("pointcut()")public void before() {log.info(" before... ");}//环绕通知@Around("pointcut()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {log.info(" around... before ... ");//SpringAop会将连接点信息都封装到joinPoint中,通过jointPoint调用目标对象的原始方法执行Object result = joinPoint.proceed();log.info(" around... after ... ");return result;}//目标方法正确返回后通知@AfterReturning("pointcut()")public void afterReturning() {log.info(" afterReturning... ");}//目标方法抛出异常后通知@AfterThrowing("pointcut()")public void afterThrowing() {log.info(" afterThrowing... ");}//后置通知@After("pointcut()")public void after() {log.info(" after... ");}}
多个切面类同类型通知的执行顺序

多个切面类中,相同类型的通知,默认是按照切面类的类名字母排序:

在这里插入图片描述

目标方法前的通知方法:字母排名靠前的先执行

目标方法后的通知方法:字母排名靠前的后执行

一般情况下,切面类的类名都是具有特殊意义的,我们无法通过类名来控制通知的执行顺序,因此我们可以使用Spring提供的@Order注解来控制通知的执行顺序。

@Component
@Aspect
@Slf4j
@Order(3)
public class Aspect3 {@Before("execution(* com.ryuki.springaopquickstart.service.imp.*.*(..))")public void before() {log.info("Aspect3.....before... ");}@After("execution(* com.ryuki.springaopquickstart.service.imp.*.*(..))")public void after() {log.info("Aspect3....after... ");}
}====================================================@Component
@Aspect
@Slf4j
@Order(2)
public class Aspect4 {@Before("execution(* com.ryuki.springaopquickstart.service.imp.*.*(..))")public void before() {log.info("Aspect4.....before... ");}@After("execution(* com.ryuki.springaopquickstart.service.imp.*.*(..))")public void after() {log.info("Aspect4....after... ");}
}====================================================@Component
@Aspect
@Slf4j
@Order(1)
public class Aspect5 {@Before("execution(* com.ryuki.springaopquickstart.service.imp.*.*(..))")public void before() {log.info("Aspect5.....before... ");}@After("execution(* com.ryuki.springaopquickstart.service.imp.*.*(..))")public void after() {log.info("Aspect5....after... ");}
}

对于前置通知而言,@Order中数字越小越先执行;后置通知中@Order数字越小越后执行。

在这里插入图片描述


小结

SpringAOP底层是基于动态代理技术来实现的,当程序运行时会自动基于动态代理技术为目标对象生成一个相应的代理对象,代理对象就会基于切面类中的逻辑对目标对象当中的原始方法进行功能上的增强。

此外,在我们注入相应的bean对象时注入的是SpringAOP创建的代理对象:

在这里插入图片描述

http://www.dtcms.com/a/420700.html

相关文章:

  • 检测网站访问量电脑做网站用word
  • 怎么建网站青州问枫上海建设银行长宁区各分行网站
  • 自建网站怎么做后台管理系统开发手机软件
  • 网站推广的途径网站维护与建设ppt
  • 网站推广方案注意事项制作视频的软件手机
  • 网站制作上网做带字头像的网站
  • 重庆做蔬菜配送的网站有哪些城市建设游戏模拟网站
  • 化妆品销售网站的源代码前端网站论文
  • 怎么做简单地网站电子商务网站管理系统完美版
  • YOLOv8训练过程中参数的设置
  • 有哪些网站可以做青旅义工wordpress数据表格
  • 做内贸要在哪个网站找客户asp网站开发报告
  • 每日前端宝藏库 | Tippy.js ✨
  • MariaDB 数据库管理指南
  • 桂林企业网站建设珠海网站制作推广公司哪家好
  • Windows 命令提示符键盘快捷键
  • 爱站seo排名可以做哪些网站网页设计师的认识
  • UI自动化框架之Selenium简介(一)
  • 做家装壁纸的网站企业名称注册查询官网入口
  • 站长做什么网站赚钱网络优化网站 site
  • 个人网站建设架构手机网站建设的行情
  • 网站建设运营费用预算承德网站建设咨询
  • 建网站要使用哪些软件南京宜电的网站谁做的
  • 手机网站app生成360建筑网会员
  • dw 做网站的思路网站优化 网站建设公司
  • 网站记录ip 修改济宁市建设工程质量监督站网站
  • 建筑图纸网站黑帽seo优化软件
  • 地产公司做网站维护写代码么6wordpress数据库分离
  • 想做cpa 没有网站怎么做应用市场商店
  • QML之二导航,通过选项卡的按键切换界面