Spring AOP 五大通知类型

前言

小伙伴们有兴趣想了解内容和更多相关学习资料的请点赞收藏+评论转发+关注我,后面会有很多干货。我有一些面试题、架构、设计类资料可以说是程序员面试必备!

所有资料都整理到网盘了,需要的话欢迎下载!私信我回复【666】即可免费获取

一、通知类型

Advice 直译为通知,也有人翻译为 “增强处理”,共有 5 种类型,如下表所示。

Spring AOP 五大通知类型_第1张图片

二、环境准备

添加 AOP 依赖

在pom.xml文件里添加 Spring AOP 和 AspectJ 的 jar 包依赖


    
    
        org.springframework
        spring-context
        5.2.10.RELEASE
    
    
    
        org.aspectj
        aspectjweaver
        1.9.5
    


复制代码

创建目标接口和实现类

/*UserDao接口*/
public interface UserDao {
    public void save();
    public int update();
}
/*UserDaoImpl实现类*/
@Repository
public class UserDaoImpl implements UserDao {
    @Override
    public void save() {
        System.out.println("正在执行 UserDao 的 save 方法");
    }
    @Override
    public int update() {
        System.out.println("正在执行 UserDao 的 update 方法");
        return 1;
    }
}

复制代码

创建通知类

  • 创建通知类,并指定切入点

/*通知类*/
@Component//将这个类定义成 Bean
@Aspect//将这个Bean定义为切面
public class MyAdvice {
    //指定UserDao类中的save方法为切入点
    @Pointcut("execution(void com.bighorn.dao.UserDao.save())")
    private void pt1(){}
    //指定UserDao类中的update方法为切入点
    @Pointcut("execution(int com.bighorn.dao.UserDao.update())")
    private void pt2(){}
}

复制代码

创建 Spring 核心配置类

/*Spring核心配置类*/
@Configuration
@ComponentScan("com.bighorn") //开启注解扫描
@EnableAspectJAutoProxy //开启 AspectJ 的自动代理
public class SpringConfig {
}

复制代码

编写运行程序

public class App {
    public static void main(String[] args) throws SQLException {
        //获取配置类初始化容器
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        //从容器中获取UserDao对象
        UserDao userDao = context.getBean(UserDao.class);
        //调用userDao的方法
        userDao.save();
    }
}

复制代码

三、添加通知

普通通知

在MyAdvice这个通知类中添加前置通知后置通知返回后通知异常后通知及相关注解。

//前置通知
@Before("pt1()")
public void before() {
    System.out.println("before advice ...");
}
//后置通知
@After("pt1()")
public void after() {
    System.out.println("after advice ...");
}
//返回后通知
@AfterReturning("pt1()")
public void afterReturning() {
    System.out.println("afterReturning advice ...");
}
//异常后通知
@AfterThrowing("pt1()")
public void afterThrowing() {
    System.out.println("afterThrowing advice ...");
}

复制代码

  • 观察运行 App 程序后的截图,发现并没有显示异常后通知

Spring AOP 五大通知类型_第2张图片

  • 手动在save()方法中添加一行代码:int i = 1/0,造成异常后再次运行 App。
  • 发现异常后通知有了,但是运行后通知却消失了。

Spring AOP 五大通知类型_第3张图片

  • 综上所述: 前置通知和后置通知是一定会执行的,而返回后通知是需要在原始方法正常执行后才会被执行,异常后通知是需要原始方法抛出异常才会被执行

环绕通知(重点)

环绕通知是非常强大的通知,能够完成上述四种通知的所有功能

/**
     * 环绕通知需要携带ProceedingJoinPoint类型的参数
     * 环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法
     * 环绕通知必须要有返回值,返回值即为目标方法的返回值
     * @param pjp
     * @return Object
     */
@Around("pt2()")
public Object around(ProceedingJoinPoint pjp) {
    Object result = null;
    try {
        System.out.println("这是环绕通知中的前置通知......");
        //执行目标方法
        result = pjp.proceed();
        System.out.println("这是环绕通知中的返回通知......");
    } catch (Throwable e) {
        System.out.println("这是环绕通知中的异常通知......");
    }
    System.out.println("这是环绕通知中的后置通知......");
    return result;
}

复制代码

修改 App 类,调用 UserDao 的update()方法,运行程序,观察结果。

public class App {
    public static void main(String[] args) throws SQLException {
        //获取配置类初始化容器
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        //从容器中获取UserDao对象
        UserDao userDao = context.getBean(UserDao.class);
        //调用userDao的update方法
        userDao.update();
    }
}

复制代码

运行结果如下Spring AOP 五大通知类型_第4张图片

 

重点

  1. 使用环绕通知必须传入形参ProceedingJoinPoint,并使用pjp.proceed()方法实现对原始方法的调用,进而实现原始方法调用前后同时添加通知
  2. 通知中如果未使用使用pjp.proceed()方法实现对原始方法的调用,则将跳过原始方法的执行
  3. 原始方法的返回值类型决定环绕通知的返回值类型。原始方法若不接收返回值,通知方法的返回值类型可以设置成 void,也可以设置成 Object;如果接收返回值,最好设定为 Object 类型
  4. 由于无法预知原始方法运行后是否会抛出异常,因此环绕通知方法必须要处理 Throwable 异常

你可能感兴趣的:(spring,java,后端)