Spring之路(44)–Spring AOP通知类型详解与实例展示

简介: 本文目录1. 通知是干啥的2. 前置通知演示3. 正常返回通知演示4. 异常返回通知演示5. 返回通知演示6. 环绕通知演示7. 总结

1. 通知是干啥的

上一篇我们演示了一种通知,即使用@Before标识的在接入点执行的方法。通知就是切面要执行的特定行为。


实际上通知很灵活,还有其他种类的通知,具体如下:


注解 名称 说明

前置通知 @Before 在实际方法调用之前调用被注解的通知方法

正常返回通知 @AfterReturning 实际方法执行完毕后执行该通知,注意抛出异常则不会执行该通知

异常返回通知 @AfterThrowing 实际执行方法抛出异常执行该通知

返回通知 @After 实际方法调用之后执行该通知,不论是否发生异常

环绕通知 @Around 方法执行之前和之后都可以执行通知指定动作,这个比较强大

2. 前置通知演示

还是车辆出门前登记这个场景,注意通知参数可以携带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

轿车出门


3. 正常返回通知演示

直接在切面类中添加通知即可,非常简单,注意如果抛出异常,该通知是不执行的。


  // 正常返回通知

  @AfterReturning("execution(public void out())")

  public void AfterReturning(JoinPoint joinPoint) {

   System.out.println("车辆已出门");

  }


4. 异常返回通知演示

在切面中定义异常返回通知,如下:


// 异常返回通知

@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("卡车进门");

}

}


5. 返回通知演示

返回通知是不管是否发生异常,都会执行的,示例如下:


// 返回通知(不论是否有异常都会执行)

  @After("execution(public void out())")

  public void after(JoinPoint joinPoint) {

   System.out.println("车辆出门这个事我知道了");// 接入方法信息

  }


6. 环绕通知演示

环绕通知能够在目标方法执行之前、之后启动,如果要记录一个方法的执行时间,那么使用环绕通知是很合适的,如下:


// 环绕通知,记录方法执行时间

  @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));

  }


7. 总结

看到这里,想必大家也能深深体会AOP的强大和作用了,例如我们完全可以针对一些指定的方法启用事务,利用环绕通知在方法开始前开启事务,在方法执行后提交事务,发生异常时回滚。


Spring AOP是功能封装的利器,当项目中越来越多的使用到AOP时,说明已逐渐从初级的Java工程师向中级进阶啦,恭喜!

相关文章
|
2月前
|
XML Java 数据安全/隐私保护
Spring Aop该如何使用
本文介绍了AOP(面向切面编程)的基本概念和术语,并通过具体业务场景演示了如何在Spring框架中使用Spring AOP。文章详细解释了切面、连接点、通知、切点等关键术语,并提供了完整的示例代码,帮助读者轻松理解和应用Spring AOP。
Spring Aop该如何使用
|
2月前
|
监控 安全 Java
什么是AOP?如何与Spring Boot一起使用?
什么是AOP?如何与Spring Boot一起使用?
74 5
|
2月前
|
Java 开发者 Spring
深入解析:Spring AOP的底层实现机制
在现代软件开发中,Spring框架的AOP(面向切面编程)功能因其能够有效分离横切关注点(如日志记录、事务管理等)而备受青睐。本文将深入探讨Spring AOP的底层原理,揭示其如何通过动态代理技术实现方法的增强。
80 8
|
2月前
|
Java 开发者 Spring
Spring高手之路24——事务类型及传播行为实战指南
本篇文章深入探讨了Spring中的事务管理,特别是事务传播行为(如REQUIRES_NEW和NESTED)的应用与区别。通过详实的示例和优化的时序图,全面解析如何在实际项目中使用这些高级事务控制技巧,以提升开发者的Spring事务管理能力。
63 1
Spring高手之路24——事务类型及传播行为实战指南
|
2月前
|
Java 开发者 Spring
Spring AOP 底层原理技术分享
Spring AOP(面向切面编程)是Spring框架中一个强大的功能,它允许开发者在不修改业务逻辑代码的情况下,增加额外的功能,如日志记录、事务管理等。本文将深入探讨Spring AOP的底层原理,包括其核心概念、实现方式以及如何与Spring框架协同工作。
|
2月前
|
XML 监控 安全
深入调查研究Spring AOP
【11月更文挑战第15天】
49 5
|
2月前
|
Java 开发者 Spring
Spring AOP深度解析:探秘动态代理与增强逻辑
Spring框架中的AOP(Aspect-Oriented Programming,面向切面编程)功能为开发者提供了一种强大的工具,用以将横切关注点(如日志、事务管理等)与业务逻辑分离。本文将深入探讨Spring AOP的底层原理,包括动态代理机制和增强逻辑的实现。
51 4
|
3月前
|
存储 缓存 Java
Spring高手之路23——AOP触发机制与代理逻辑的执行
本篇文章深入解析了Spring AOP代理的触发机制和执行流程,从源码角度详细讲解了Bean如何被AOP代理,包括代理对象的创建、配置与执行逻辑,帮助读者全面掌握Spring AOP的核心技术。
57 3
Spring高手之路23——AOP触发机制与代理逻辑的执行
|
2月前
|
Java Spring
[Spring]aop的配置与使用
本文介绍了AOP(面向切面编程)的基本概念和核心思想。AOP是Spring框架的核心功能之一,通过动态代理在不修改原代码的情况下注入新功能。文章详细解释了连接点、切入点、通知、切面等关键概念,并列举了前置通知、后置通知、最终通知、异常通知和环绕通知五种通知类型。
45 1
|
2月前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
46 0