嗨客网搜索

JavaEE Spring AOP通知类型

描述

Spring AOP 的通知类型有五种,分别为前置、后置、异常、最终、环绕。

题目

搭建 Spring 的开发环境,运用 Spring AOP 不同的通知类型对目标方法进行增强。

题目解决思路

  1. 创建 Maven 项目
  2. pom.xml 导入相关依赖。
  3. 创建目标对象和切面对象。
  4. 完成核心配置文件的相关配置。

项目结构

41_JavaEE Spring.png

前期准备

pom 文件:

<?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>net.haicoder</groupId> <artifactId>SpringDemo13</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <!--IOC依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.7.RELEASE</version> </dependency> <!--AOP依赖--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.7</version> </dependency> </dependencies> </project>

代码具体实现

核心配置文件:

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!--创建目标对象--> <bean id="userService" class="net.haicoder.service.impl.UserServiceImpl"/> <!--创建切面对象--> <bean id="logAspect" class="net.haicoder.aop.LogAspect"/> <!--配置切面--> <aop:config> <!--创建切点--> <aop:pointcut id="pt" expression="execution(* net.haicoder.service.impl.UserServiceImpl.save(..))"/> <!--创建切面--> <aop:aspect ref="logAspect" > <!--前置通知--> <aop:before method="before" pointcut-ref="pt"/> <!--后置通知--> <aop:after-returning method="afterReturning" pointcut-ref="pt"/> <!--异常通知--> <aop:after-throwing method="afterThrowing" pointcut-ref="pt"/> <!--最终通知--> <aop:after method="after" pointcut-ref="pt"/> </aop:aspect> </aop:config> </beans>

切面类:

public class LogAspect { /** * 1. 前置通知方法 */ public void before(){ System.out.println("【前置通知】:写入日志..."); } /** * 2. 后置通知方法 */ public void afterReturning(){ System.out.println("【后置通知】:写入日志..."); } /** * 3. 异常通知方法 */ public void afterThrowing(){ System.out.println("【异常通知】:写入日志..."); } /** * 4. 最终通知方法 */ public void after(){ System.out.println("【最终通知】:写入日志..."); } }

业务层接口:

public interface UserService { void save(); }

业务层实现类:

public class UserServiceImpl implements UserService{ @Override public void save() { System.out.println("【用户操作】:保存用户!"); } }

测试类:

public class DemoTest { public static void main(String[] args) { System.out.println("嗨客网(www.haicoder.net)\n"); ApplicationContext act = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = (UserService) act.getBean("userService"); userService.save(); } }

运行结果

演示一(前置、后置、最终)

目标对象没有异常时,运行结果如下:

42_JavaEE Spring.png

演示二(前置、后置、异常、最终)

需要在目标方法中,模拟一个异常,修改 UserServiceImpl 代码如下:

public class UserServiceImpl implements UserService{ @Override public void save() { int i = 10/0; System.out.println("【用户操作】:保存用户!"); } }

运行结果如下:

43_JavaEE Spring.png

演示三(环绕通知)

在切面类中增加环绕通知方法,如下:

public class LogAspect { /** * 1. 前置通知方法 */ public void before(){ System.out.println("【前置通知】:写入日志..."); } /** * 2. 后置通知方法 */ public void afterReturning(){ System.out.println("【后置通知】:写入日志..."); } /** * 3. 异常通知方法 */ public void afterThrowing(){ System.out.println("【异常通知】:写入日志..."); } /** * 4. 最终通知方法 */ public void after(){ System.out.println("【最终通知】:写入日志..."); } /** * 5. 环绕通知方法 */ public Object around(ProceedingJoinPoint joinPoint){ try{ System.out.println("【前置通知】:写入日志..."); // 执行目标对象的方法 Object result = joinPoint.proceed(); System.out.println("【后置通知】:写入日志..."); return result; }catch (Throwable throwable){ throwable.printStackTrace(); System.out.println("【异常通知】:写入日志..."); throw new RuntimeException(throwable); }finally { System.out.println("【最终通知】:写入日志..."); } } }

修改核心配置文件,如下:

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!--创建目标对象--> <bean id="userService" class="net.haicoder.service.impl.UserServiceImpl"/> <!--创建切面对象--> <bean id="logAspect" class="net.haicoder.aop.LogAspect"/> <!--配置切面--> <aop:config> <!--创建切点--> <aop:pointcut id="pt" expression="execution(* net.haicoder.service.impl.UserServiceImpl.save(..))"/> <!--创建切面--> <aop:aspect ref="logAspect" > <!--环绕通知--> <aop:around method="around" pointcut-ref="pt"/> </aop:aspect> </aop:config> </beans>

目标对象没有异常时,运行结果如下:

44_JavaEE Spring.png

在目标方法中,模拟一个异常,修改 UserServiceImpl 代码如下:

public class UserServiceImpl implements UserService{ @Override public void save() { int i = 10/0; System.out.println("【用户操作】:保存用户!"); } }

目标对象有异常时,运行如下:

45_JavaEE Spring.png

总结

通过以上案例,我们得出 Spring AOP 的通知类型有五种,分别为前置、后置、异常、最终、环绕,其中环绕通知综合了前四种通知的执行效果。

在目标方法没有异常的情况下,执行顺序如下:

  • 前置通知

  • 目标方法

  • 后置通知

  • 最终通知

在目标方法存在异常的情况下,执行顺序如下:

  • 前置通知

  • 目标方法抛出异常

  • 异常通知

  • 最终通知

嗨客网顶部