Spring:AOP通知类型

我们先来回顾下AOP通知:

  • AOP通知描述了抽取的共性功能,根据共性功能抽取的位置不同,最终运行代码时要将其加入到合理的位置

通知具体要添加到切入点的哪里?

共提供了5种通知类型:

  • 前置通知
  • 后置通知
  • 环绕通知(重点)
  • 返回后通知(了解)
  • 抛出异常后通知(了解)

为了更好的理解这几种通知类型,我们来看一张图

(1)前置通知,追加功能到方法执行前,类似于在代码1或者代码2添加内容

(2)后置通知,追加功能到方法执行后,不管方法执行的过程中有没有抛出异常都会执行,类似于在代码5添加内容

(3)返回后通知,追加功能到方法执行后,只有方法正常执行结束后才进行,类似于在代码3添加内容,如果方法执行抛出异常,返回后通知将不会被添加

(4)抛出异常后通知,追加功能到方法抛出异常后,只有方法执行出异常才进行,类似于在代码4添加内容,只有方法抛出异常后才会被添加

(5)环绕通知,环绕通知功能比较强大,它可以追加功能到方法执行的前后,这也是比较常用的方式,它可以实现其他四种通知类型的功能,具体是如何实现的,需要我们往下学习。

示例学习:

1,创建一个Maven项目

2,pom.xml添加Spring依赖

xml 复制代码
<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>6.1.14</version>
  </dependency>
  <dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.4</version>
  </dependency>
</dependencies>

3,添加BookDao和BookDaoImpl类

java 复制代码
public interface BookDao {
    public void update();
    public int select();
}

@Repository
public class BookDaoImpl implements BookDao {
    public void update(){
        System.out.println("book dao update ...");
    }
    public int select() {
        System.out.println("book dao select is running ...");
        return 100;
    }
}

4,创建Spring的配置类

java 复制代码
@Configuration
@ComponentScan("com.itheima")
@EnableAspectJAutoProxy
public class SpringConfig {
}

5,创建通知类

java 复制代码
@Component
@Aspect
public class MyAdvice {
  @Pointcut("execution(void com.itheima.dao.BookDao.update())")
  private void pt(){}
  @Pointcut("execution(int com.itheima.dao.BookDao.select())")
  private void pt2(){}

  //@Before:前置通知,在原始方法运行之前执行
  @Before("pt()")
  public void before() {
      System.out.println("before advice ...");
  }

  //@After:后置通知,在原始方法运行之后执行
  @After("pt2()")
  public void after() {
      System.out.println("after advice ...");
  }

  //@Around:环绕通知,在原始方法运行的前后执行
  @Around("pt()")
  public Object around(ProceedingJoinPoint pjp) throws Throwable {
      System.out.println("around before advice ...");
      //表示对原始操作的调用
      Object ret = pjp.proceed();
      System.out.println("around after advice ...");
      return ret;
  }

  @Around("pt2()")
  public Object aroundSelect(ProceedingJoinPoint pjp) throws Throwable {
      System.out.println("around before advice ...");
      //表示对原始操作的调用
      Integer ret = (Integer) pjp.proceed();
      System.out.println("around after advice ...");
      return ret;
  }

  //@AfterReturning:返回后通知,在原始方法执行完毕后运行,且原始方法执行过程中未出现异常现象
  @AfterReturning("pt2()")
  public void afterReturning() {
      System.out.println("afterReturning advice ...");
  }

  //@AfterThrowing:抛出异常后通知,在原始方法执行过程中出现异常后运行
  @AfterThrowing("pt2()")
  public void afterThrowing() {
      System.out.println("afterThrowing advice ...");
  }
}

6,编写App运行类

java 复制代码
public class App {
  public static void main(String[] args) {
      ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
      BookDao bookDao = ctx.getBean(BookDao.class);
      int num = bookDao.select();
      System.out.println(num);
      bookDao.update();
  }
}

7,运行结果

结论

  • 如果对同一个切点有多个通知类型,则按照出现的顺序都会增强

  • 如果我们使用环绕通知的话,要根据原始方法的返回值来设置环绕通知的返回值:Object ret = pjp.proceed();

    • 为什么返回的是Object而不是int的主要原因是Object类型更通用。
    • 在环绕通知中是可以对原始方法返回值就行修改的。
  • 返回后通知是需要在原始方法select正常执行后才会被执行,如果select()方法执行的过程中出现了异常,那么返回后通知是不会被执行。后置通知是不管原始方法有没有抛出异常都会被执行。

  • 学习完这5种通知类型,我们来思考下环绕通知是如何实现其他通知类型的功能的?
    因为环绕通知是可以控制原始方法执行的,所以我们把增强的代码写在调用原始方法的不同位置就可以实现不同的通知类型的功能,如:

    • 环绕通知注意事项
    1. 环绕通知必须依赖形参ProceedingJoinPoint才能实现对原始方法的调用,进而实现原始方法调用前后同时添加通知
    2. 通知中如果未使用ProceedingJoinPoint对原始方法进行调用将跳过原始方法的执行
    3. 对原始方法的调用可以不接收返回值,通知方法设置成void即可,如果接收返回值,最好设定为Object类型
    4. 原始方法的返回值如果是void类型,通知方法的返回值类型可以设置成void,也可以设置成Object
    5. 由于无法预知原始方法运行后是否会抛出异常,因此环绕通知方法必须要处理Throwable异常

通知类型总结

知识点1:@After
名称 @After
类型 方法注解
位置 通知方法定义上方
作用 设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法后运行
知识点2:@AfterReturning
名称 @AfterReturning
类型 方法注解
位置 通知方法定义上方
作用 设置当前通知方法与切入点之间绑定关系,当前通知方法在原始切入点方法正常执行完毕后执行
知识点3:@AfterThrowing
名称 @AfterThrowing
类型 方法注解
位置 通知方法定义上方
作用 设置当前通知方法与切入点之间绑定关系,当前通知方法在原始切入点方法运行抛出异常后执行
知识点4:@Around
名称 @Around
类型 方法注解
位置 通知方法定义上方
作用 设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法前后运行

[说明]:内容主要来源黑马程序员网上资源学习

相关推荐
scott.cgi6 小时前
Unity直接编译Java文件作为插件,导致失败的两个打包设置
java·unity·unity调用java·unity的java文件·unity的android插件·unity调用android·unity加载java代码
澈20710 小时前
C++并查集:高效解决连通性问题
java·c++·算法
易安说AI10 小时前
Codex 直接住进 JetBrains IDE 里:AI Agent 正在接管熟悉的开发入口
后端
子兮曰11 小时前
Node.js v26.1.0 深度解读:FFI、后量子密码与调试器的进化
前端·后端·node.js
霸道流氓气质11 小时前
基于 Milvus Lite 的 Spring AI RAG 向量库实践方案与示例
人工智能·spring·milvus
2401_8734794012 小时前
运营活动被薅羊毛怎么防?用IP查询+设备指纹联动封堵漏洞
java·网络·tcp/ip·github
ShiJiuD66688899912 小时前
大事件板块一
java
摇滚侠12 小时前
@Autowired 和 @Resource 的区别
java·开发语言
Wy_编程12 小时前
go语言中的结构体
开发语言·后端·golang
SeaTunnel12 小时前
(八)收官篇 | 数据平台最后一公里:数据集成开发设计与上线治理实战
java·大数据·开发语言·白鲸开源