Spring AOP的5种通知类型

1. AOP通知分类

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

  • AOP通知共分为5种类型
    • 前置通知:在切入点方法执行之前执行
    • 后置通知:在切入点方法执行之后执行,无论切入点方法内部是否出现异常,后置通知都会执行。
    • ==环绕通知(重点):==手动调用切入点方法并对其进行增强的通知方式。
    • 返回后通知:在切入点方法执行之后执行,如果切入点方法内部出现异常将不会执行。
    • 抛出异常后通知:在切入点方法执行之后执行,只有当切入点方法内部出现异常之后才执行。

2. AOP通知详解

2.1 前置通知

  • 名称:@Before
  • 类型:方法注解
  • 位置:通知方法定义上方
  • 作用:设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法前运行
  • 范例:
@Before("pt()")
public void before() {
    
    
    System.out.println("before advice ...");
}

2.2 后置通知

  • 名称:@After
  • 类型:方法注解
  • 位置:通知方法定义上方
  • 作用:设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法后运行
  • 范例:
@After("pt()")
public void after() {
    
    
    System.out.println("after advice ...");
}

2.3 返回后通知

  • 名称:@AfterReturning(了解)
  • 类型:方法注解
  • 位置:通知方法定义上方
  • 作用:设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法正常执行完毕后运行
  • 范例:
@AfterReturning("pt()")
public void afterReturning() {
    
    
    System.out.println("afterReturning advice ...");
}

2.4 抛出异常后通知

  • 名称:@AfterThrowing(了解)
  • 类型:方法注解
  • 位置:通知方法定义上方
  • 作用:设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法运行抛出异常后执行
  • 范例:
@AfterThrowing("pt()")
public void afterThrowing() {
    
    
    System.out.println("afterThrowing advice ...");
}

2.5 环绕通知

  • 名称:@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;
}

环绕通知注意事项

  1. 环绕通知方法形参必须是ProceedingJoinPoint,表示正在执行的连接点,使用该对象的proceed()方法表示对原始对象方法进行调用,返回值为原始对象方法的返回值。
  2. 环绕通知方法的返回值建议写成Object类型,用于将原始对象方法的返回值进行返回,哪里使用代理对象就返回到哪里。
  3. 环绕通知中可以对原始方法调用过程中出现的异常进行处理
  4. 环绕通知可以隔离原始方法的调用执行

3. 代码案例

项目结构如下:
在这里插入图片描述
导入依赖:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.yyl</groupId>
  <artifactId>spring_20_aop_advice_type</artifactId>
  <version>1.0-SNAPSHOT</version>

  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.10.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.4</version>
    </dependency>
  </dependencies>
</project>

编写配置类,开启切面编程配置

package com.yyl.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan("com.yyl")
@EnableAspectJAutoProxy
public class SpringConfig {
    
    
}

编写接口与实现类

package com.yyl.dao;

public interface BookDao {
    
    
    public void update();

    public int select();
}

package com.yyl.dao.impl;

import com.yyl.dao.BookDao;
import org.springframework.stereotype.Repository;

@Repository
public class BookDaoImpl implements BookDao {
    
    

    public void update(){
    
    
        System.out.println("book dao update is running ...");
    }

    public int select() {
    
    
        System.out.println("book dao select is running ...");
//        int i = 1/0;
        return 100;
    }
}

编写通知类,我们使用5种通知类型 分别配置 update与save方法上

package com.yyl.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class MyAdvice {
    
    
    @Pointcut("execution(void com.yyl.dao.BookDao.update())")
    private void pt(){
    
    }
    @Pointcut("execution(int com.yyl.dao.BookDao.select())")
    private void pt2(){
    
    }

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

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

    //@After:后置通知,在原始方法运行之后执行
    @After("pt()")
    public void afterpt() {
    
    
        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 ...");
    }
}

运行结果如下图所示:
在这里插入图片描述
接下来我们将save中的除0操作取消注释

int i = 1/0;

再运行,发现运行异常通知
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_45525272/article/details/125955962
今日推荐