【Java】SpringAOP —— AOP是什么? 代码实现了SpringAOP

本文介绍了AOP(面向切面编程)的概念,包括切面、连接点、切点和通知的组成。详细讲解了SpringAOP中的各种通知类型,并展示了如何在SpringBoot项目中添加AOP框架支持和定义切点与通知。
摘要由CSDN通过智能技术生成


一、AOP是什么

AOP(Aspect Oriented Programming):面向切面编程,它是⼀种思想,它是对某一类事情的集中处理。

就比如用户登录验证,一个网站的绝大部分功能,都要验证用户是否登录,因此就要在大多数功能中添加用户登录验证的代码或调用用户登录验证的方法,这是相当繁琐的,后期的开发维护成本也很高。

而AOP则可以解决这一问题。

对于这种功能统一,且频繁使用的功能,就可以使用AOP来统一处理了。


二、AOP的组成

  1. 切面(Aspect):由切点(Pointcut)和通知(Advice)组成,它既包含了横切逻辑的定义,也包
    括了连接点的定义。
  2. 连接点(Join Point):程序执行中可以插入切面的一个点,可以是方法调用时,抛出异常时等等。
  3. 切点(Pointcut):Pointcut 的作用就是提供⼀组规则(使用 AspectJ pointcut expression language 来描述)来匹配 Join Point,给满足规则的 连接点 添加 通知。
  4. 通知(Advice):切面也是有目标的 ——它必须完成的工作。在 AOP 术语中,切面的工作被称之为通知。通知定义了切面是什么,何时使用,其描述了切面要完成的⼯作,还解决何时执行这个工作的问题。

切面就相当于加工厂,连接点是公司的待加工物品,切点是规定那些物品可以进行加工,通知则是加工这些物品


三、SpringAOP

Spring 切面类中,可以在方法上使用以下注解,会设置方法为通知方法,在满足条件后会通知本方法进行调用:

  • 前置通知使用 @Before:通知方法会在目标方法调用之前执行。
  • 后置通知使用 @After:通知方法会在目标方法返回或者抛出异常后调用。
  • 返回之后通知使用 @AfterReturning:通知方法会在目标方法返回后调用。
  • 抛异常后通知使用 @AfterThrowing:通知方法会在目标方法抛出异常后调用。
  • 环绕通知使用 @Around:通知包裹了被通知的方法,在被通知的方法通知之前和调用之后执
    行⾃定义的行为。

切点表达式说明:
AspectJ 支持三种通配符
* :匹配任意字符,只匹配⼀个元素(包,类,或方法,方法参数)
.. :匹配任意字符,可以匹配多个元素 ,在表示类时,必须和 * 联合使⽤。
+ \ :表示按照类型匹配指定类的所有类,必须跟在类名后面,如com.cad.Car+ ,表示继承该类的所有子类包括本身
切点表达式由切点函数组成,其中 execution() 是最常用的切点函数,用来匹配方法,语法为:

execution(<修饰符><返回类型><包.类.方法(参数)><异常>)
修饰符与异常一般省略

返回值:{void}无返回,{String}返回字符串,{*}任意

:{com.example.demo} 固定包demo包; {com.example.demo.*} demo包下任意包不包括demo包;{com.example.demo..}demo包下任意包 包括demo包;

: {Demo}固定类Demo类;{de*}以De开头的类;{*mo}以mo结尾的类;{*}任意类

方法名:{function}固定方法function方法;{fun*}以fun开头的方法;{*tion}以tion结尾的方法;{*}任意方法

参数:{}无参;{int} 一个整型参数;{int,int}两个整型参数;{..}任意参数


四、实现SpringAOP

1.添加AOP框架支持

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2.定义切面切点

匹配方法的规则可以有多个,即可以有多个切点,切点方法不需要有方法体,只是需要这个方法名起一个标识作用.

@Aspect // 定义切面
@Component
public class UserAspect {

    // 切点
    @Pointcut("execution(* com.example.demo.Controller.UserController.*(..))")
    public void pointcutA(){}

    // 切点
    @Pointcut("execution(* com.example.demo.Controller.ArticleController.*(..))")
    public void pointcutB(){}



3.定义相关通知

通过注解来让方法变为通知方法,注解中填写切点的方法名来区分不同切点

@Aspect // 定义切面
@Component
public class UserAspect {

    // 切点
    @Pointcut("execution(* com.example.demo.Controller.UserController.*(..))")
    public void pointcutA(){}

    // 切点
    @Pointcut("execution(* com.example.demo.Controller.ArticleController.*(..))")
    public void pointcutB(){}

    // 前置通知
    @Before("pointcutA()")
    public void doBefore() {
        System.out.println("执行了前置通知");
    }

    // 后置通知
    @After("pointcutA()")
    public void doAfter() {
        System.out.println("执行了后置通知");
    }

    // 返回后通知
    @AfterReturning("pointcutA()")
    public void doAfterReturning() {
        System.out.println("执行了返回后通知");
    }

    // 抛出异常后通知
    @AfterThrowing("pointcutA()")
    public void doAfterThrowing() {
        System.out.println("抛出异常后通知");
    }

    // 环绕通知
    @Around("pointcutA()")
    public Object doAround(ProceedingJoinPoint joinPoint) {
        System.out.println("环绕通知开始执行");
        Object result = null;
        try {
        	// 执行目标方法
            result = joinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("环绕通知执行完毕");
        return result;
    }
}

环绕通知比较特殊,它必须要传入参数 ProceedingJoinPoint joinPoint ,该参数相当于符合切点规则且触发切面的方法;joinPoint.proceed(); 则是执行该方法.
在这里插入图片描述

其中do getUser为连接点的输出内容
在这里插入图片描述


  • 21
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值