springboot提升-切面编程

2024-09-06 05:36

本文主要是介绍springboot提升-切面编程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 开发步骤
      • 1. 引入依赖
      • 2. 创建切面类
        • 示例切面类:
      • 3. 定义切入点表达式
        • 示例切入点表达式:
      • 4. 使用注解定义通知
        • 示例通知:
      • 5. 自动装配切面类
      • 6. 测试切面功能
      • 注意事项
    • 切面注解
      • 常用的切面注解
      • 示例代码
      • 注意事项
    • 切面语法
      • 示例 1: 匹配特定的方法
      • 示例 2: 匹配所有公共方法
      • 示例 3: 匹配所有方法
      • 示例 4: 匹配特定包下的所有方法
      • 示例 5: 匹配具有特定参数的方法
      • 示例 6: 匹配特定返回类型的方法
      • 示例 7: 匹配没有参数的方法
      • 示例 8: 匹配特定异常的方法
      • 示例 9: 匹配特定方法签名

开发步骤

在 Spring Boot 中使用切面(Aspect)开发可以帮助你在不修改现有业务逻辑的情况下,增加诸如日志记录、安全检查、性能监控等功能。Spring 提供了 Spring AOP(面向切面编程)的支持,它允许你定义切面来封装横切关注点(cross-cutting concerns),并通过通知(advice)来增强程序的功能。

以下是如何在 Spring Boot 中使用切面开发的基本步骤:

1. 引入依赖

确保你的项目包含 Spring AOP 的依赖。如果你使用的是 Spring Boot,则默认已经包含了 Spring AOP 的支持,因此无需额外添加依赖。

2. 创建切面类

创建一个切面类,并使用 @Aspect 注解标记它。在这个类中定义通知(Advice)方法,这些方法将在特定的连接点(join point)执行。

示例切面类:
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;@Aspect
@Component
public class LoggingAspect {private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);@Pointcut("execution(* com.example.service.*.*(..))")public void loggingPointcut() {// 无具体实现,仅作为切入点定义}@Before("loggingPointcut()")public void logBefore(JoinPoint joinPoint) {logger.info("Entering method: {}.{} with arguments: {}",joinPoint.getSignature().getDeclaringTypeName(),joinPoint.getSignature().getName(),joinPoint.getArgs());}@After("loggingPointcut()")public void logAfter(JoinPoint joinPoint) {logger.info("Exiting method: {}.{}",joinPoint.getSignature().getDeclaringTypeName(),joinPoint.getSignature().getName());}
}

在这个例子中,我们定义了一个名为 loggingPointcut 的切入点,它匹配 com.example.service 包下所有类的所有方法。logBefore 方法会在切入点匹配的方法执行前被调用,而 logAfter 方法则在方法执行后被调用。

3. 定义切入点表达式

在切面类中定义切入点表达式(pointcut expression),它可以指定何时执行通知。Spring 支持多种类型的切入点表达式,包括但不限于方法执行、异常抛出等。

示例切入点表达式:
@Pointcut("execution(* com.example.service.*.*(..))")
public void loggingPointcut() {// 无具体实现,仅作为切入点定义
}

这个表达式定义了一个名为 loggingPointcut 的切入点,它匹配 com.example.service 包下所有类的所有方法。

4. 使用注解定义通知

使用 @Before@After@Around@AfterReturning@AfterThrowing 等注解来定义不同类型的通知。

示例通知:
@Before("loggingPointcut()")
public void logBefore(JoinPoint joinPoint) {// 在切入点匹配的方法执行前的操作
}@After("loggingPointcut()")
public void logAfter(JoinPoint joinPoint) {// 在切入点匹配的方法执行后的操作
}

5. 自动装配切面类

在 Spring Boot 中,由于使用了组件扫描 (@ComponentScan),所以只需要将切面类标注为 @Component,Spring 就会自动检测并装配它们。如果你没有使用组件扫描,也可以显式地在配置类中声明切面。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class AppConfig {@Beanpublic LoggingAspect loggingAspect() {return new LoggingAspect();}
}

6. 测试切面功能

编写单元测试来验证切面是否按预期工作。你可以编写一些测试用例来触发被切面增强的方法,并检查日志输出是否符合预期。

注意事项

  • 确保切入点表达式正确无误,否则通知可能不会在预期的位置执行。
  • 谨慎使用 @Around 通知,因为它可以完全控制方法的执行流程,容易引起死锁或其他问题。
  • 如果有多个切面,需要注意它们之间的顺序,可以通过 Ordered 接口来控制顺序。

通过以上步骤,你可以在 Spring Boot 中成功地实现切面开发,从而在不侵入现有业务代码的情况下增加新的功能。

切面注解

在 Spring Boot 中,使用切面(Aspect)来进行面向切面编程(AOP)可以通过一系列注解来定义和配置切面的行为。以下是 Spring AOP 中常用的几个注解及其用途:

常用的切面注解

  1. @Aspect

    • 用于标记一个类是一个切面类。
    • 这个类将包含多个通知(Advice)方法,这些方法会在特定的连接点(Join Point)处被调用。
  2. @Component

    • 将切面类注册为 Spring Bean,确保切面类能够被 Spring 容器管理。
    • 通常与 @Aspect 结合使用。
  3. @Before

    • 用于在目标方法执行前执行通知方法。
    • 如果 @Before 通知方法抛出了异常,则不会执行目标方法。
  4. @After

    • 用于在目标方法执行后执行通知方法,无论方法是否成功执行或抛出异常。
    • 这个通知总是会被执行,除非它自己抛出了一个未处理的异常。
  5. @AfterReturning

    • 用于在目标方法成功完成后执行通知方法。
    • 如果目标方法抛出了异常,则此通知不会被执行。
  6. @AfterThrowing

    • 用于在目标方法抛出异常后执行通知方法。
    • 只有当目标方法抛出异常时,此通知才会被执行。
  7. @Around

    • 用于在目标方法执行前后都执行通知方法,可以用来实现环绕通知,如性能监视等。
    • 这种通知可以决定是否继续执行目标方法或直接返回或抛出异常。

示例代码

下面是一个简单的示例,展示了如何使用这些注解来定义一个切面:

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;@Aspect
@Component
public class LoggingAspect {// 定义一个切入点表达式,用于匹配特定的方法调用@Pointcut("execution(* com.example.demo.service.*.*(..))")public void serviceLayerExecution() {}// 在切入点处执行前置通知@Before("serviceLayerExecution()")public void logBefore(JoinPoint joinPoint) {System.out.println("Executing @Before advice on method: " + joinPoint.getSignature());}// 在切入点处执行后置通知@After("serviceLayerExecution()")public void logAfter(JoinPoint joinPoint) {System.out.println("Executing @After advice on method: " + joinPoint.getSignature());}// 在切入点处执行返回通知@AfterReturning(pointcut = "serviceLayerExecution()", returning = "result")public void logAfterReturning(JoinPoint joinPoint, Object result) {System.out.println("Executing @AfterReturning advice on method: " + joinPoint.getSignature() + ", result: " + result);}// 在切入点处执行异常通知@AfterThrowing(pointcut = "serviceLayerExecution()", throwing = "exception")public void logAfterThrowing(JoinPoint joinPoint, Exception exception) {System.out.println("Executing @AfterThrowing advice on method: " + joinPoint.getSignature() + ", exception: " + exception.getMessage());}
}

在这个示例中,我们定义了一个名为 LoggingAspect 的切面类,它包含了四种不同的通知方法,分别对应四种不同的通知类型:@Before@After@AfterReturning@AfterThrowing。这些方法会在切入点表达式 serviceLayerExecution() 指定的方法调用前后执行相应的逻辑。

注意事项

  • 确保你的 Spring Boot 应用已启用 AOP 支持,通常情况下,如果切面类上有 @Aspect@Component 注解,那么 Spring Boot 会自动识别并配置 AOP 支持。
  • 为了确保切面能够正常工作,确保切入点表达式正确无误,并且覆盖了你希望拦截的方法。
  • 考虑到性能和可维护性,尽量减少切面的复杂度,并保持切面逻辑的单一职责原则。

切面语法

在 Spring AOP 中,execution 是一个切入点表达式,用于指定哪些连接点(即方法调用)应该被切面所关注。execution 表达式允许你根据方法签名来匹配方法调用,包括返回类型、包、类、方法名以及参数列表。

execution 表达式的语法格式如下:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)

其中:

  • modifiers-pattern?:可选的修饰符模式。
  • ret-type-pattern:返回类型模式。
  • declaring-type-pattern?:可选的声明类型模式。
  • name-pattern:方法名模式。
  • param-pattern:参数模式。
  • throws-pattern?:可选的异常模式。

下面是一些具体的例子:

示例 1: 匹配特定的方法

execution(public int com.example.demo.service.MyService.myMethod(int))

这将匹配 com.example.demo.service.MyService 类中的 myMethod 方法,该方法有一个 int 类型的参数并且返回 int 类型的结果。

示例 2: 匹配所有公共方法

execution(public * *(..))

这将匹配所有公共方法,无论其返回类型或参数列表是什么。

示例 3: 匹配所有方法

execution(* *.*(..))

这将匹配所有方法,无论其返回类型、方法名称、所在类或参数列表。

示例 4: 匹配特定包下的所有方法

execution(* com.example.demo.service.*.*(..))

这将匹配 com.example.demo.service 包下所有类的所有方法。

示例 5: 匹配具有特定参数的方法

execution(* com.example.demo.service.*.*(*String*, ..))

这将匹配 com.example.demo.service 包下所有类的所有方法,只要其中一个参数是 String 类型即可。

示例 6: 匹配特定返回类型的方法

execution(String *.*(..))

这将匹配所有返回类型为 String 的方法。

示例 7: 匹配没有参数的方法

execution(* *.*() throws ..)

这将匹配所有没有参数的方法,并且允许方法抛出异常。

示例 8: 匹配特定异常的方法

execution(* *.*(..) throws java.io.IOException)

这将匹配所有可能抛出 java.io.IOException 异常的方法。

示例 9: 匹配特定方法签名

execution(* com.example.demo.service.*.get*(..))

这将匹配 com.example.demo.service 包下所有类的任何以 get 开头的方法。

使用这些表达式可以帮助你精确地控制哪些方法会被切面所影响。在编写切入点表达式时,请确保它们足够具体,以避免意外地匹配到其他你不希望影响的方法。

这篇关于springboot提升-切面编程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1141142

相关文章

Spring Cloud LoadBalancer 负载均衡详解

《SpringCloudLoadBalancer负载均衡详解》本文介绍了如何在SpringCloud中使用SpringCloudLoadBalancer实现客户端负载均衡,并详细讲解了轮询策略和... 目录1. 在 idea 上运行多个服务2. 问题引入3. 负载均衡4. Spring Cloud Load

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录

在 Spring Boot 中使用 @Autowired和 @Bean注解的示例详解

《在SpringBoot中使用@Autowired和@Bean注解的示例详解》本文通过一个示例演示了如何在SpringBoot中使用@Autowired和@Bean注解进行依赖注入和Bean... 目录在 Spring Boot 中使用 @Autowired 和 @Bean 注解示例背景1. 定义 Stud

如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解

《如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解》:本文主要介绍如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别的相关资料,描述了如何使用海康威视设备网络SD... 目录前言开发流程问题和解决方案dll库加载不到的问题老旧版本sdk不兼容的问题关键实现流程总结前言作为

SpringBoot中使用 ThreadLocal 进行多线程上下文管理及注意事项小结

《SpringBoot中使用ThreadLocal进行多线程上下文管理及注意事项小结》本文详细介绍了ThreadLocal的原理、使用场景和示例代码,并在SpringBoot中使用ThreadLo... 目录前言技术积累1.什么是 ThreadLocal2. ThreadLocal 的原理2.1 线程隔离2

springboot将lib和jar分离的操作方法

《springboot将lib和jar分离的操作方法》本文介绍了如何通过优化pom.xml配置来减小SpringBoot项目的jar包大小,主要通过使用spring-boot-maven-plugin... 遇到一个问题,就是每次maven package或者maven install后target中的ja

Java中八大包装类举例详解(通俗易懂)

《Java中八大包装类举例详解(通俗易懂)》:本文主要介绍Java中的包装类,包括它们的作用、特点、用途以及如何进行装箱和拆箱,包装类还提供了许多实用方法,如转换、获取基本类型值、比较和类型检测,... 目录一、包装类(Wrapper Class)1、简要介绍2、包装类特点3、包装类用途二、装箱和拆箱1、装

如何利用Java获取当天的开始和结束时间

《如何利用Java获取当天的开始和结束时间》:本文主要介绍如何使用Java8的LocalDate和LocalDateTime类获取指定日期的开始和结束时间,展示了如何通过这些类进行日期和时间的处... 目录前言1. Java日期时间API概述2. 获取当天的开始和结束时间代码解析运行结果3. 总结前言在J

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

最长公共子序列问题的深度分析与Java实现方式

《最长公共子序列问题的深度分析与Java实现方式》本文详细介绍了最长公共子序列(LCS)问题,包括其概念、暴力解法、动态规划解法,并提供了Java代码实现,暴力解法虽然简单,但在大数据处理中效率较低,... 目录最长公共子序列问题概述问题理解与示例分析暴力解法思路与示例代码动态规划解法DP 表的构建与意义动