Spring AOP有多少个通知以及它们的执行顺序介绍

 更新时间:2022年11月15日 10:00:45   作者:滕青山YYDS  
这篇文章主要介绍了Spring AOP有多少个通知以及它们的执行顺序,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

Spring AOP有多少个通知以及它们的执行顺序

Spring AOP有多少个通知

  • ①前置通知(Before):在连接点执行前执行该通知
  • ②正常返回通知(AfterReturning):在连接点正常执行完后执行该通知,若目标方法执行异常则不会执行该通知
  • ③异常通知(AfterThrowing):在连接点执行抛出异常时执行该通知
  • ④后置通知(after/finally):在连接点执行完成后(不管成功、失败、异常)都会执行该通知
  • ⑤环绕通知(Around):围绕在连接点前后

Spring AOP通知的执行顺序

  • ①环绕通知:@Around
  • ②前置通知:@Before
  • ③执行连接点方法
  • ④环绕通知:@Around
  • ⑤后置通知:@After
  • ⑥正常返回通知:@AfterReturning,如果发生异常那么就是异常通知@AfterThrowing

在这里插入图片描述

SpringAOP简单案例

本文是一个老师在学校给学生上课的简单案例,介绍了AOP的五个通知的使用,以及通知的执行顺序。通过自定义注解来充当切入点,获取注解的类型分别对不同的老师做对应的业务处理。

代码中的消息响应体(Result)大家可以自定义类型。

AOP的五大通知

  • 前置通知:Before
  • 环绕通知:Around
  • 后置通知:After
  • 后置返回通知:AfterReturning
  • 后置异常通知:AfterThrowing

执行顺序如下图所示:

在这里插入图片描述

AOP的使用方式

1.创建一个课题实体对象

package com.cloud.industryapi.test;

import lombok.Data;

/**
 * 课题实体
 * @date 2022/3/25 16:26
 */
@Data
public class ArticleEntity {

    /**
     * PK
     */
    private Integer id;

    /**
     * 课题
     */
    private String title;

    /**
     * 内容
     */
    private String content;

}

2.定义一个切入点,这里以自定义注解的方式实现

package com.cloud.industryapi.test;

import java.lang.annotation.*;

/**
 * 切点标识
 * @author 
 * @date 2022/3/25 13:09
 */
@Target({ElementType.METHOD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PointcutId {
    
    String type() default "";
}

3.声明要织入的切面

package com.cloud.industryapi.test;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * 切面
 */
@Slf4j
@Aspect
@Component
public class ArticleAspect {

    /**
     * 定义切入点
     */
    @Pointcut("@annotation(com.cloud.industryapi.test.PointcutId)")
    public void pointcut(){

    }

    /**
     * 环绕通知
     * @param joinPoint
     * @param id
     * @return
     * @throws Throwable
     */
    @Around("pointcut() && @annotation(id)")
    public Object around(ProceedingJoinPoint joinPoint, PointcutId id) throws Throwable {
        log.info("-------------around start-------------");
        Object[] objects = joinPoint.getArgs();
        switch (id.type()){
            case "language":
                ArticleEntity language = (ArticleEntity) objects[0];
                log.info("-------------语文老师课前备课,课题:{}-------------",language.getTitle());
                break;
            case "mathematics":
                log.info("-------------数学老师课前备课-------------");
                break;
            default:
                throw new RuntimeException("类型非法");
        }
        //joinPoint.proceed()
        Object s = joinPoint.proceed();
        log.info("-------------叮铃铃铃铃...放学了-------------");
        log.info("-------------around end-------------");
        return s;
    }

    /**
     * 前置通知
     * @param joinPoint
     * @param id
     */
    @Before("pointcut()  && @annotation(id)")
    public void before(JoinPoint joinPoint,PointcutId id){
        log.info("-------------before start-------------");
        log.info("-------------学生进入教室,准备上课-------------");
        log.info("-------------before end-------------");
    }

    /**
     * 后置通知
     * @param joinPoint
     * @param id
     */
    @After("pointcut() && @annotation(id)")
    public void after(JoinPoint joinPoint,PointcutId id){
        log.info("-------------after start-------------");
        log.info("-------------学校广播:老师们,同学们,中午好,今天学校食堂免费为你们准备了烧鸡,人手一鸡-------------");
        log.info("-------------after end-------------");
    }

    /**
     * 后置返回通知
     * @param joinPoint
     * @param id
     */
    @AfterReturning("pointcut() && @annotation(id)")
    public void afterReturn(JoinPoint joinPoint, PointcutId id){
        log.info("-------------AfterReturning-------------");
        log.info("-------------老师们同学们拿着烧鸡回家了-------------");
        log.info("-------------学校关闭了大门-------------");
        log.info("-------------AfterReturning-------------");
    }

    /**
     * 后置异常通知
     * @param joinPoint
     * @param id
     */
    @AfterThrowing("pointcut() && @annotation(id)")
    public void afterThrow(JoinPoint joinPoint,PointcutId id){
        log.info("-------------AfterThrowing-------------");
        log.info("-------------完蛋,小明同学迷路了。。。-------------");
        log.info("-------------AfterThrowing-------------");
    }
}

注意:ProceedingJoinPoint的proceed()方法相当于前置通知和后置通知的分水岭。

说明:ProceedingJoinPoint的proceed()方法在执行前用来做一些 

  • 例如:读取日志 ,然后执行目标方法。ProceedingJoinPoint的proceed()方法执行后 ,用来做一些 
  • 例如:写入日志\color{#0000FF}{说明:ProceedingJoinPoint的proceed()方法在执行前用来做一些
  • 例如:读取日志,然后执行目标方法。ProceedingJoinPoint的proceed()方法执行后,用来做一些
  • 例如:写入日志}说明:ProceedingJoinPoint的proceed()方法在执行前用来做一些
  • 例如:读取日志,然后执行目标方法。ProceedingJoinPoint的proceed()方法执行后,用来做一些
  • 例如:写入日志

4.编写控制器

package com.cloud.industryapi.test;

import com.cloud.common.kit.Result;
import com.cloud.common.page.FrontPagination;
import com.cloud.industry.dto.ExclusiveJumpConfigDto;
import com.cloud.industry.facede.ExclusiveJumpConfigFacede;
import com.cloud.industry.qo.ExclusiveJumpConfigQo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * 文章 - 控制器
 */
@Slf4j
@RestController
@RequestMapping("/aop/test")
public class ArticleController {

    /**
     * 后置异常通知
     */
    @PointcutId
    @RequestMapping("/afterThrow")
    public void afterThrow(){
        log.info("-------------------进入了目标方法-------------------");
        System.out.println(2/0);
    }
    
    /**
     * 语文课
     *
     * @param ae
     * @return
     */
    @PointcutId(type = "language")
    @PostMapping("/language")
    public Result language(@RequestBody ArticleEntity ae) {
        log.info("-------------目标方法开始执行-------------");
        log.info("-------------语文老师进入教室,开始讲课《"+ae.getTitle()+"》-------------");
        System.out.printf("%s","深蓝的天空中挂着一轮金黄的圆月,下面是海边的沙地,都种着一望无际的碧绿的西瓜。\n" +
                "其间有一个十一二岁的少年,项带银圈,手捏一柄钢叉,向一匹猹尽力的刺去。\n" +
                "那猹却将身一扭,反从他的胯下逃走了。\n");
        log.info("-------------目标方法结束执行-------------");
        return Result.success("执行结束");
    }

    /**
     * 数学课
     *
     * @param ae
     * @return
     */
    @PointcutId(type = "mathematics")
    @PostMapping("/mathematics")
    public Result mathematics(@RequestBody ArticleEntity ae) {
        log.info("-------------目标方法开始执行-------------");
        log.info("-------------数学老师进入教室-------------");
        log.info("-------------“同学们,今天这节数学课,由我代上”-------------");
        log.info("-------------“起立”-------------");
        log.info("-------------”体~育~老~师~好~~“-------------");
        log.info("-------------目标方法结束执行-------------");
        return Result.success("执行结束");
    }
}

5.请求控制器

最后是请求的响应

完成

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java雪花算法的实现详解

    Java雪花算法的实现详解

    雪花算法(Snowflake)是一种分布式唯一ID生成算法,用于生成全局唯一的ID,使用雪花算法生成的ID通常是一个64位的整数,可以根据需要进行转换和展示,在Java等编程语言中,可以使用相应的库或工具来生成雪花算法的ID,本文给大家介绍了Java雪花算法的实现
    2023-11-11
  • Java服务器宕机的解决方法论

    Java服务器宕机的解决方法论

    这篇文章主要介绍了Java服务器宕机的解决方法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • Springboot整合Flowable6.x导出bpmn20的步骤详解

    Springboot整合Flowable6.x导出bpmn20的步骤详解

    这篇文章主要介绍了Springboot整合Flowable6.x导出bpmn20,Flowable流程引擎可用于部署BPMN 2.0流程定义,可以十分灵活地加入你的应用/服务/构架,本文给出两种从flowable导出流程定义bpmn20.xml的方式,需要的朋友可以参考下
    2023-04-04
  • spring boot补习系列之几种scope详解

    spring boot补习系列之几种scope详解

    这篇文章主要给大家介绍了关于spring boot补习系列之几种scope的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用spring boot具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-07-07
  • 在SpringBoot中使用MongoDB的简单场景案例

    在SpringBoot中使用MongoDB的简单场景案例

    MongoDB 是一种非关系型数据库,也被称为 NoSQL 数据库,它主要以文档的形式存储数据,本文给大家介绍了在SpringBoot中使用MongoDB的简单场景案例,并通过代码示例讲解的非常详细,需要的朋友可以参考下
    2024-09-09
  • Java 基础详解(泛型、集合、IO、反射)

    Java 基础详解(泛型、集合、IO、反射)

    下面小编就为大家带来一篇Java 基础详解(泛型、集合、IO、反射)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-10-10
  • Java并发编程深入理解之Synchronized的使用及底层原理详解 上

    Java并发编程深入理解之Synchronized的使用及底层原理详解 上

    在并发编程中存在线程安全问题,主要原因有:1.存在共享数据 2.多线程共同操作共享数据。关键字synchronized可以保证在同一时刻,只有一个线程可以执行某个方法或某个代码块,同时synchronized可以保证一个线程的变化可见(可见性),即可以代替volatile
    2021-09-09
  • Java连接Mysql数据库详细代码实例

    Java连接Mysql数据库详细代码实例

    这篇文章主要介绍了Java连接Mysql数据库详细代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • Java中Servlet的生命周期

    Java中Servlet的生命周期

    这篇文章主要介绍了Java中Servlet的生命周期,Servlet 初始化后调用 init () 方法、Servlet 调用 service() 方法来处理客户端的请求、Servlet 销毁前调用 destroy() 方法,下面来看看具体的解析吧,需要的小伙伴可以参考一下
    2022-01-01
  • java 线程池keepAliveTime的含义说明

    java 线程池keepAliveTime的含义说明

    这篇文章主要介绍了java 线程池keepAliveTime的含义说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02

最新评论