本文将详细为大家介绍SpringAOP的五种通知类型(前置通知、后置通知、返回通知、异常通知、环绕通知),感兴趣的朋友可以了解一下
一、通知类型
Advice
直译为通知,也有人翻译为 “增强处理”,共有 5 种类型,如下表所示。
通知类型 | 注解 | 说明 |
---|---|---|
before(前置通知) | @Before | 通知方法在目标方法调用之前执行 |
after(后置通知) | @After | 通知方法在目标方法返回或异常后调用 |
after-returning(返回通知) | @AfterReturning | 通知方法会在目标方法返回后调用 |
after-throwing(异常通知) | @AfterThrowing | 通知方法会在目标方法抛出异常后调用 |
around(环绕通知) | @Around | 通知方法会将目标方法封装起来 |
二、环境准备
添加AOP依赖
在pom.xml
文件里添加Spring AOP和AspectJ的jar包依赖
<dependencies>
<!--包含Spring AOP:有基本的AOP功能-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<!--AspectJ框架有更强大的AOP功能-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
</dependencies>
创建目标接口和实现类
/*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程序后的截图,发现并没有显示异常后通知
手动在save()
方法中添加一行代码:int i = 1/0
,造成异常后再次运行App。
发现异常后通知有了,但是运行后通知却消失了。
综上所述: 前置通知和后置通知是一定会执行的,而返回后通知是需要在原始方法正常执行后才会被执行,异常后通知是需要原始方法抛出异常才会被执行
环绕通知(重点)
环绕通知是非常强大的通知,能够完成上述四种通知的所有功能。
/**
* 环绕通知需要携带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();
}
}
运行结果如下
注意点
使用环绕通知必须传入形参ProceedingJoinPoint
,并使用pjp.proceed()方法
实现对原始方法的调用,进而实现原始方法调用前后同时添加通知
通知中如果未使用使用pjp.proceed()方法
实现对原始方法的调用,则将跳过原始方法的执行
原始方法的返回值类型决定环绕通知的返回值类型。原始方法若不接收返回值,通知方法的返回值类型可以设置成void,也可以设置成Object;如果接收返回值,最好设定为Object类型。
由于无法预知原始方法运行后是否会抛出异常,因此环绕通知方法必须要处理Throwable异常
以上就是一文搞懂Spring AOP的五大通知类型的详细内容,更多关于Spring AOP通知类型的资料请关注编程学习网其它相关文章!
本文标题为:一文搞懂Spring AOP的五大通知类型
基础教程推荐
- java基础知识之FileInputStream流的使用 2023-08-11
- Java实现线程插队的示例代码 2022-09-03
- java实现多人聊天系统 2023-05-19
- Java实现查找文件和替换文件内容 2023-04-06
- springboot自定义starter方法及注解实例 2023-03-31
- Java文件管理操作的知识点整理 2023-05-19
- ConditionalOnProperty配置swagger不生效问题及解决 2023-01-02
- JDK数组阻塞队列源码深入分析总结 2023-04-18
- Java数据结构之对象比较详解 2023-03-07
- Java并发编程进阶之线程控制篇 2023-03-07