Spring之路(44)–Spring AOP通知类型详解与实例展示
2020/2/18 8:08:36
本文主要是介绍Spring之路(44)–Spring AOP通知类型详解与实例展示,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
通知是干啥的
上一篇我们演示了一种通知,即使用@Before
标识的在接入点执行的方法。通知就是切面要执行的特定行为。
实际上通知很灵活,还有其他种类的通知,具体如下:
注解 | 名称 | 说明 |
---|---|---|
前置通知 | @Before | 在实际方法调用之前调用被注解的通知方法 |
正常返回通知 | @AfterReturning | 实际方法执行完毕后执行该通知,注意抛出异常则不会执行该通知 |
异常返回通知 | @AfterThrowing | 实际执行方法抛出异常执行该通知 |
返回通知 | @After | 实际方法调用之后执行该通知,不论是否发生异常 |
环绕通知 | @Around | 方法执行之前和之后都可以执行通知指定动作,这个比较强大 |
前置通知演示
还是车辆出门前登记这个场景,注意通知参数可以携带JoinPoint
参数,该参数中包含被通知的方法信息、还有目标对象的信息,这样便于我们操作。
第一,货车类和轿车类,提供容器中bean的类型信息。
package org.maoge.aopdemo.useaop; /** * 货车 */ public class Truck { public void out() { System.out.println("卡车出门"); } public void in() { System.out.println("卡车进门"); } }
package org.maoge.aopdemo.useaop; /** * 轿车 */ public class Car { public void out() { System.out.println("轿车出门"); } public void in() { System.out.println("轿车进门"); } }
第二,在配置类中将类型注册为bean,同时开启AOP,开启指定包的bean扫描。
package org.maoge.aopdemo.useaop; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; /** * 配置类 */ @Configuration // 配置类,用来配置容器 @EnableAspectJAutoProxy // 开启AOP @ComponentScan(basePackages = { "org.maoge.aopdemo.useaop" }) // 扫描包以便发现注解配置的bean public class SpringConfig { @Bean // 注册卡车bean public Truck Truck() { Truck truck = new Truck(); return truck; } @Bean // 注册轿车bean public Car car() { Car car = new Car(); return car; } }
第三,配置切面,并编写前置通知
package org.maoge.aopdemo.useaop; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; /** * 车辆出门切面 */ @Component // 切面也是Spring的bean @Aspect // 使用该注解标志此类是一切面 public class OutAspect { // 前置通知 @Before("execution(public void out())")//在public void out()方法之前执行通知 public void outNote(JoinPoint joinPoint) { System.out.println("出门登记信息"); System.out.println("joinPoint.signature:" + joinPoint.getSignature());// 接入方法信息 System.out.println("joinPoint.target.class.name:" + joinPoint.getTarget().getClass().getName());// 接入目标对象的类型信息 } }
第四,测试类
package org.maoge.aopdemo.useaop; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Main { public static void main(String[] args) { // 获取容器 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); // 取出bean Truck truck = (Truck) context.getBean(Truck.class); // 执行bean方法 truck.out(); Car car = (Car) context.getBean(Car.class); car.out(); } }
执行结果如下,可见前置通知执行成功,且已输出接入点方法信息和目标对象信息。
出门登记信息 joinPoint.kind:method-execution joinPoint.signature:void org.maoge.aopdemo.useaop.Truck.out() joinPoint.target.class.name:org.maoge.aopdemo.useaop.Truck 卡车出门 出门登记信息 joinPoint.kind:method-execution joinPoint.signature:void org.maoge.aopdemo.useaop.Car.out() joinPoint.target.class.name:org.maoge.aopdemo.useaop.Car 轿车出门
正常返回通知演示
直接在切面类中添加通知即可,非常简单,注意如果抛出异常,该通知是不执行的。
// 正常返回通知 @AfterReturning("execution(public void out())") public void AfterReturning(JoinPoint joinPoint) { System.out.println("车辆已出门"); }
异常返回通知演示
在切面中定义异常返回通知,如下:
// 异常返回通知 @AfterThrowing("execution(public void out())") public void afterThrowing(JoinPoint joinPoint) { System.out.println(joinPoint.getSignature()+"发生异常");// 接入方法信息 }
注意必须抛出才能执行该通知,如果方法内部处理了异常,则不会执行异常返回通知,如下:
package org.maoge.aopdemo.useaop; /** * 轿车 */ public class Car { //抛出异常,会执行异常通知 public void out() { System.out.println("轿车出门"); int a=1/0; } public void in() { System.out.println("轿车进门"); } }
package org.maoge.aopdemo.useaop; /** * 货车 */ public class Truck { //已处理异常,不会执行异常通知 public void out() { System.out.println("卡车出门"); try { int a=1/0; }catch(Exception e) { } } public void in() { System.out.println("卡车进门"); } }
返回通知演示
返回通知是不管是否发生异常,都会执行的,示例如下:
// 返回通知(不论是否有异常都会执行) @After("execution(public void out())") public void after(JoinPoint joinPoint) { System.out.println("车辆出门这个事我知道了");// 接入方法信息 }
环绕通知演示
环绕通知能够在目标方法执行之前、之后启动,如果要记录一个方法的执行时间,那么使用环绕通知是很合适的,如下:
// 环绕通知,记录方法执行时间 @Around("execution(public void out())") public void around(ProceedingJoinPoint joinPoint) throws Throwable { long startTime = System.currentTimeMillis();//开始时间 joinPoint.proceed();//这一行代码表示执行目标方法 System.out.println(joinPoint.getSignature() + "运行时间(毫秒)为:" + (System.currentTimeMillis() - startTime)); }
我们来看下输出:
出门登记信息 joinPoint.signature:void org.maoge.aopdemo.useaop.Truck.out() joinPoint.target.class.name:org.maoge.aopdemo.useaop.Truck 卡车出门 void org.maoge.aopdemo.useaop.Truck.out()运行时间(毫秒)为:7 车辆出门这个事我知道了 车辆已出门 出门登记信息 joinPoint.signature:void org.maoge.aopdemo.useaop.Car.out() joinPoint.target.class.name:org.maoge.aopdemo.useaop.Car 轿车出门 车辆出门这个事我知道了 void org.maoge.aopdemo.useaop.Car.out()发生异常 Exception in thread "main" java.lang.ArithmeticException: / by zero
可见没有异常的时候,统计运行时间成功了,当发生异常时,环绕通知中抛出异常,未能执行到打印运行时间那一行,所以改为:
// 环绕通知,记录方法执行时间 @Around("execution(public void out())") public void around(ProceedingJoinPoint joinPoint) { long startTime = System.currentTimeMillis();// 开始时间 try { joinPoint.proceed();// 这一行代码表示执行目标方法 } catch (Throwable e) { e.printStackTrace(); } System.out.println(joinPoint.getSignature() + "运行时间(毫秒)为:" + (System.currentTimeMillis() - startTime)); }
总结
看到这里,想必大家也能深深体会AOP的强大和作用了,例如我们完全可以针对一些指定的方法启用事务,利用环绕通知在方法开始前开启事务,在方法执行后提交事务,发生异常时回滚。
Spring AOP是功能封装的利器,当项目中越来越多的使用到AOP时,说明已逐渐从初级的Java工程师向中级进阶啦,恭喜!
这篇关于Spring之路(44)–Spring AOP通知类型详解与实例展示的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-05-13TiDB + ES:转转业财系统亿级数据存储优化实践
- 2024-05-09“2024鸿蒙零基础快速实战-仿抖音App开发(ArkTS版)”实战课程已上线
- 2024-05-09聊聊如何通过arthas-tunnel-server来远程管理所有需要arthas监控的应用
- 2024-05-09log4j2这么配就对了
- 2024-05-09nginx修改Content-Type
- 2024-05-09Redis多数据源,看这篇就够了
- 2024-05-09Google Chrome驱动程序 124.0.6367.62(正式版本)去哪下载?
- 2024-05-09有没有大佬知道这种数据应该怎么抓取呀?
- 2024-05-09这种运行结果里的10.100000001,怎么能最快改成10.1?
- 2024-05-09企业src漏洞挖掘-有意思的命令执行