Springboot_4-AOP

Spring-Aop

aop是spring核心特性之一,全称为面向切面编程,推荐了解完java中的反射与代理再阅读此篇文章

作用:

简单来说,aop是用来处理业务之外的事,比如用来进行记录操作日志,权限控制,事务管理,公共字段自动填充等等.

举个通俗的例子,在你书写spring模块时,在controller层你会处理用户的请求、调用业务逻辑,并返回相应的数据,此时有个需求,要求你去记录在控制层执行的方法,每执行一次方法,都需要记录执行了什么方法,返回了什么,出现了什么异常;当你是个小白,你会想:简单我直接找到控制层所有方法,在方法逻辑代码前加一个输出语句,在return前加一个输出语句,再将业务逻辑全都用try-catch包起来不就是了;想法很美好,现实很骨感;方法实在太多了,处理起来太麻烦了,而且每个方法名你无法让他自动获取,都得手写.(用输出语句代替将日志内容存入数据库)

但是经过学习,你知道了可以用__动态代理__技术来解决:创建一个全能的代理对象用来操控service层,再在invoke方法中处理对应日志逻辑,只需要将在控制层自动注入的service组件交给代理对象,调用方法时使用代理对象调用即可,再也不用香控制层方法中慢慢的写重复代码了,工作的轻松了不少.

可过段时间你发现,每次用都得将service对象交给代理对象,而且由于获取得还是service层得方法名,有时会和控制层方法名有冲突;你不禁想:难道spring就没有一种简单得方法,我只需要说明这些在业务逻辑之外要做什么,他就会在业务方法执行时,自动插入我书写的代码.

这就是__AOP__的由来:帮助开发者在不改变业务逻辑代码的情况下,处理一些其他事情;–让你少做一些重复的事,想修改这些事也会变得更简单,不用一个一个改(减少代码耦合性)

名词介绍

刚开始学习aop时你可能会对一些名词感到疑惑,我来介绍他们的大致意思

一个方法执行大概分为:方法开始->方法返回/方法异常/方法无返回->方法结束,这是每个方法都有的阶段,每个方法不同阶段都是不一样的,每个方法也都是不一样的;所以我们可以将任意方法的每个阶段都看出不同的东西,就叫连接点吧,当执行每个连接点时,spring就会拦截他,来通知你写的方法(处理业务逻辑之外的哪些方法),告诉他来活的,快加工加工;但是并不是每个连接点都需要加工,这样spring先回累死;所以需要你去筛选需要的连接点(从自己感兴趣的地方切入),这些特殊的连接点就被称为连接点;你写的这些处理业务逻辑之外的方法作用各异,有记录日志的,有管理事务的,为了方便自己管理与日后修改,你把作用不同的方法放入不同的类中,叫做切面类

79ddba2fc5f4cb72898e909364e7c556

切面(Aspect):一个关注点的模块化,通常用来定义跨越多个类的功能(如日志、事务管理等)。

连接点(Join Point):程序执行中的一个点,比如方法调用、异常抛出等。

切点(Pointcut):定义了在哪些连接点上应用切面的表达式。->从连接点中寻找要特定执行的方法点位

通知(Advice):(通知要去干什么)切面在特定切点上执行的动作,分为不同类型:

目标(Target):被切面所代理的对象。

书写切面类

了解完概念就可以来书写自己的切面类:书写一个记录操作的切面类

  1. 建立一个包专门管理切面类,在包里创建一个切面类来管理日志-LogAspect
  2. 在类名上添加@Aspect(表示是个切面类,给人看的)和@Component(将切面类放入容器中,不然spring调用不了)
  3. 书写切点表达式来筛选切点
  4. 书写通知方法(切点要执行什么)
切入点表达式与通知类型

这两个主要是解决通知方法在何时何地运行->筛选连接点;比如说我写了个在方法执行前记录日志的方法,此方法我想他作用在userController类中;如何确保他在方法执行前运行,又如何确定他在特定方法时才生效呢?

***** 切入点表达式-确定作用在哪里:

通常是用execution(方法的全签名)

//切点表达式-execution中一定要有的东西:方法返回值类型,方法名,参数类型,*表示任意字符
//..:在参数位置表示任意个参数,任意类型,在类型位置表示多个层级

如何用表达式表示userController的所有方法呢:execution(* com.zhang.controller.UserController.*(…))->第一个星是表达所有类型的返回值,第二个星是表达userController的所有方法,(…)是说明方法参数是任意的.

还可以使用异或符号:execution(* com.example.service.UserService.addUser()) || execution(* com.example.service.UserService.deleteUser())

***** 通知类型-确定何时生效

前置通知(@Before(切点表达式)):在目标方法执行之前执行的通知。可以用于记录日志、检查权限等操作。

后置通知(@After(切点表达式)):在目标方法执行之后,无论方法成功与否都会执行的通知。通常用于清理资源或记录日志。

返回通知(@AfterReturning(切点表达式)):在目标方法正常执行完毕后执行的通知。可以获取方法返回值。

异常通知(@AfterThrowing(切点表达式)):在目标方法抛出异常后执行的通知。用于处理异常或记录错误信息。

环绕通知(@Around(切点表达式)):在目标方法执行前后执行的通知,可以控制目标方法的执行,并可以修改目标方法参数,执行结果等

通知

关于通知方法书写规范只强调一点,那就是通知的方法参数,通知的方法参数只能为空或者为JoinPoint类,若为其他类型spring在工作时拿到通知方法参数时发现与规定中的不同,便会出现异常.

JoinPoint类代表的就是连接点,提供了关于目标方法的信息,有三个常用方法

getSignature()//获取方法签名信息。->获取的是Signature类,通常为了获取更详细的信息都会将其强制转换为他的子接口MethodSignature
//Signature:当你只需要获取基本的签名信息(如方法名称、声明类型)时使用。
//MethodSignature:当你需要更详细的方法信息(如返回类型、参数类型、注解等)时使用。(子接口)

getArgs():获取方法参数。
getTarget():获取目标对象。

也可以通过反射操作目标方法参数中的方法

代码
@Aspect//标记此类为切面类
@Component//放入容器中切面类才会生效
public class LogAspect {
   //切入点表达式的缩写
   @Pointcut("execution(int com.zhang.aop.calculation.MathCal.*(int,int))")
    public void qie(){}

    //通知:通知类型
    @Before("qie()")
    public void bef(JoinPoint joinPoint){
        //此是为了返回方法名
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        System.out.println(methodSignature.getName());
        System.out.println("日志:方法"+methodSignature.getName()+"被执行"+ Arrays.toString(joinPoint.getArgs()));
    }
}

多切面的执行顺序

关于有两个或以上的切面类的执行顺序在此不做过多说明,就是一个核心思想:一个切面就是一个代理对象(简称A),另一个切面代理的是A->简单来说就是把一个切面类以及目标方法整个看成另一个切面类的目标方法,以此类推

d88de8b1028832d91dec9170adfde1c1

@Order(int)

由此就衍生出类另一个问题:那我怎么知道到底那个切面先执行,那个后执行呢–>看首字母顺序(spring中很多执行顺序默认都是看首字母大写),首字母A最先执行;

那我想要控制切面执行顺序该怎么办:使用@Order(int a)注解,a越小,此切面类的执行顺序就越高;

作用

通过对AOP的学习,来再探讨AOP的作用->为了以后遇到而想到使用AOP

  1. 日志记录(Logging)
    AOP可以在方法调用前、后或异常时插入日志记录逻辑,无需修改业务逻辑代码。这样可以集中管理日志记录,提升代码的可维护性。
  2. 性能监控(Performance Monitoring)
    可以通过AOP在应用程序的关键部分添加性能监控代码,比如计算方法执行时间等。这有助于识别系统中的性能瓶颈。
  3. 事务管理(Transaction Management)
    AOP用于声明性事务管理,事务逻辑可以独立于业务逻辑,通过注解或XML配置来处理事务,而不需要在业务逻辑中显式编写事务管理代码。
  4. 安全控制(Security)->以后会结合springSecurity使用
    可以通过AOP来实现安全检查,例如在进入某些方法之前检查当前用户是否有权限。这避免了将安全检查逻辑混入业务代码中,使安全逻辑与业务逻辑分离。
  5. 异常处理(Exception Handling)
    AOP可以用于集中处理异常,特别是跨多个层次的应用中。通过在切面中捕获和处理异常,避免业务代码中散布大量的try-catch块。
  6. 缓存管理(Caching)
    使用AOP可以实现自动缓存结果,避免重复执行耗时的操作。在方法调用时,可以通过切面拦截检查缓存,决定是否从缓存中获取数据或者执行实际的方法。

总结

对于AOP来说,需要知道aop的应用场景,也就是作用,会写切面类(切点表达式与通知),这样在日后使用会越发得心应手.

关于aop通知中的环绕通知我会特地开一篇文章说明

学习完可以思考以下问题

切入点与连接点的关系

如何让spring知道各个通知在何时何地运行

出现异常会执行前置,后置通知吗?

通知中唯一可用的参数类型?

关于通知的类型

切点表达式的书写

组件执行优先级设置@Order

多切面执行顺序

如何书写切面类

什么是AOP

通知中的异常与返回类型执行的通知的注解参数

为什么动态代理必须要为接口实现类->因为动态代理会生成目标对象接口的接口实现类作为代理对象,没有接口就不会出现代理对象

关于通知的类型

切点表达式的书写

组件执行优先级设置@Order

多切面执行顺序

如何书写切面类

什么是AOP

通知中的异常与返回类型执行的通知的注解参数

为什么动态代理必须要为接口实现类->因为动态代理会生成目标对象接口的接口实现类作为代理对象,没有接口就不会出现代理对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值