首页 > 其他分享 >Spring 6 AOP

Spring 6 AOP

时间:2024-08-02 08:55:06浏览次数:10  
标签:calculate Spring Calculator AOP result 通知 方法 method

Spring 6 AOP

概述

AOP(Aspect Oriented Programming)即面向切面编程,是Spring框架中一个非常重要的特性。它允许开发者在不修改源代码的情况下,对程序进行横向的增强,如日志记录、事务管理、性能监控等。AOP将横切关注点(cross-cutting concerns)与业务逻辑分离,提高了代码的可维护性和重用性。

基础概念

切面(Aspect)

切面是跨越多个类的关注点的模块化,如日志、事务管理等。切面由切点和增强(通知)组成。

切点(Pointcut)

切点定义了增强应该应用到哪些连接点(JoinPoint)上。连接点是程序执行过程中能够插入增强的点,通常是方法的执行。

通知(Advice)

通知定义了增强的具体行为,包括在何时执行增强。Spring AOP支持五种类型的通知:

  • 前置通知(Before Advice):在目标方法执行前执行。
  • 后置通知(After Advice):在目标方法执行后执行,不关心方法执行结果。
  • 返回通知(After Returning Advice):在目标方法成功执行后执行,可以访问返回值。
  • 异常通知(After Throwing Advice):在目标方法抛出异常后执行。
  • 环绕通知(Around Advice):在目标方法执行前后都执行,并且可以决定是否继续执行目标方法。

织入(Weaving)

织入是将切面应用到目标对象并创建代理对象的过程,这个过程由Spring框架自动完成。

示例代码

1. 定义目标类

首先,我们定义一个简单的目标类,该类包含一个方法calculate

@Component
public class Calculator {

    public int calculate(int a, int b) {
        return a + b;
    }
}

2. 定义切面类

接下来,我们定义一个切面类,该类包含前置通知、后置通知、返回通知和异常通知。

@Aspect
@Component
public class LoggingAspect {

    // 定义切点
    @Pointcut("execution(* com.example.demo.Calculator.*(..))")
    public void calculatorOperation() {}

    // 前置通知
    @Before("calculatorOperation()")
    public void beforeAdvice(JoinPoint joinPoint) {
        System.out.println("Before method: " + joinPoint.getSignature().getName());
    }

    // 后置通知
    @After("calculatorOperation()")
    public void afterAdvice(JoinPoint joinPoint) {
        System.out.println("After method: " + joinPoint.getSignature().getName());
    }

    // 返回通知
    @AfterReturning(pointcut = "calculatorOperation()", returning = "result")
    public void afterReturningAdvice(JoinPoint joinPoint, Object result) {
        System.out.println("After returning method: " + joinPoint.getSignature().getName() + " with result: " + result);
    }

    // 异常通知
    @AfterThrowing(pointcut = "calculatorOperation()", throwing = "exception")
    public void afterThrowingAdvice(JoinPoint joinPoint, Throwable exception) {
        System.out.println("After throwing method: " + joinPoint.getSignature().getName() + " with exception: " + exception.getMessage());
    }

    // 环绕通知
    @Around("calculatorOperation()")
    public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("Before proceeding method: " + proceedingJoinPoint.getSignature().getName());
        Object result = proceedingJoinPoint.proceed(); // 继续执行目标方法
        System.out.println("After proceeding method: " + proceedingJoinPoint.getSignature().getName() + " with result: " + result);
        return result;
    }
}

3. 配置类

确保Spring能够扫描到切面类和目标类,并且启用了AspectJ自动代理。

@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages = "com.example.demo")
public class AppConfig {
}

4. 测试类(续)

@SpringBootTest
public class AopTest {

    @Autowired
    private Calculator calculator;

    @Test
    public void testCalculate() {
        int result = calculator.calculate(1, 2);
        System.out.println("Test result: " + result);
        
        // 预期输出将包括AOP的通知输出,例如前置通知、后置通知、返回通知的输出
    }

    @Test
    public void testCalculateWithException() {
        // 假设Calculator类中有一个可能抛出异常的方法,我们在这里模拟测试
        // 例如,通过反射调用一个不存在的方法或修改calculate方法以抛出异常
        // 注意:这里仅作为示例,实际中可能需要根据实际情况修改Calculator类或添加新方法
        
        // 由于我们的Calculator类没有直接抛出异常的方法,这里我们假设有一个类似的情况
        // 为了简化,我们直接在测试方法中抛出异常,并验证异常通知是否生效
        try {
            // 假设这里调用了一个会抛出异常的方法
            throw new RuntimeException("Test Exception");
        } catch (Exception e) {
            // 异常捕获只是为了模拟,实际中不需要这样做
            // 真正的异常捕获和处理应该在被AOP增强的方法中
            // 这里不会输出AOP的异常通知,因为异常不是从Calculator类的方法中抛出的
            // 如果要测试异常通知,需要在Calculator类中添加一个可能抛出异常的方法
        }
        
        // 注意:上面的代码不会触发Calculator类的异常通知,因为异常不是在Calculator的方法中抛出的
        // 若要测试异常通知,请确保Calculator类中有可能抛出异常的方法,并在该方法上调用它
    }
}

注意:上述testCalculateWithException方法中的异常模拟并不直接触发Calculator类中的异常通知,因为异常是在测试方法中直接抛出的,而不是通过Calculator类的方法。为了测试异常通知,你需要在Calculator类中添加一个可能抛出异常的方法,并在测试中调用该方法。

5. 运行测试

运行上述测试类中的testCalculate方法,你将看到控制台输出了AOP的前置通知、后置通知和返回通知的日志。由于testCalculate方法中的calculate方法没有抛出异常,所以不会看到异常通知的输出。
测试类的运行结果将取决于你实际编写的代码和配置。然而,基于我们之前定义的Calculator类和LoggingAspect切面,以及假设的testCalculate测试方法,运行该测试类将输出类似于以下内容的日志(假设使用的是Spring Boot的测试支持,并且所有配置都正确无误):

Before method: calculate
Before proceeding method: calculate
After proceeding method: calculate with result: 3
After returning method: calculate with result: 3
After method: calculate
Test result: 3

这里是对输出日志的解释:

  • Before method: calculate:这是前置通知的输出,它在calculate方法执行前被调用。
  • Before proceeding method: calculate:这是环绕通知中,在继续执行目标方法前的部分。注意,环绕通知同时包含了前置和后置的逻辑,但在这里我们将其前置部分单独列出以与前置通知区分。
  • After proceeding method: calculate with result: 3:这是环绕通知中,在目标方法执行并获取结果后的部分。它输出了方法的名称和结果。
  • After returning method: calculate with result: 3:这是返回通知的输出,它在目标方法成功执行并返回结果后被调用。
  • After method: calculate:这是后置通知的输出,它在目标方法执行后被调用,不论方法是否成功执行或抛出异常。
  • Test result: 3:这是测试方法中打印的结果,显示了calculate方法的返回值。

然而,请注意,After throwing method: ...这样的日志输出不会出现在这个场景中,因为calculate方法没有抛出异常。如果你想要测试异常通知,你需要在Calculator类中定义一个可能抛出异常的方法,并在测试类中调用它。

另外,如果你使用的是JUnit或Spring Boot Test来运行测试,你可能还需要在测试类上添加一些注解来启用Spring的测试支持,比如@SpringBootTest@RunWith(SpringRunner.class)(尽管在Spring Boot 2.x中,@RunWith(SpringRunner.class)通常可以被@SpringBootTest所取代)。

最后,请确保你的项目已经包含了Spring AOP的依赖,并且Spring Boot的配置能够扫描到你的切面类和目标类。

总结

通过以上示例,我们展示了如何在Spring 6中使用AOP进行方法增强的基本步骤,包括定义目标类、切面类、配置类和测试类。AOP是Spring框架中一个非常强大的特性,能够极大地提高代码的可维护性和重用性。通过合理地使用AOP,我们可以将日志记录、事务管理、安全检查等横切关注点与业务逻辑分离,使得代码更加清晰和易于管理。

标签:calculate,Spring,Calculator,AOP,result,通知,方法,method
From: https://blog.csdn.net/2401_83447580/article/details/140791494

相关文章

  • 【SpringBoot】集成Redis
    目录1redis1.1特点1.2支持的数据类型1.3应用场景2安装redis2.1docker3可视化软件3.1RedisDesktopManager(RDM)3.2QuickRedis(推荐)4SpringBoot集成4.1引入redis4.2.操作redis4.2.1直接操作4.3分布式会话场景(Resis-Session)1redis​ redis是一个用C语言开发的,基于内......
  • spring集成elasticsearch并实现基础功能
    什么是elasticsearch?Elasticsearch是一个基于Lucene的开源搜索引擎和分析引擎,它为结构化和非结构化的海量数据提供了实时的搜索、分析和可视化功能。Elasticsearch是ElasticStack(也称为ELKStack)的核心组件之一,其他组件还包括Kibana(用于数据可视化)、Logstash(用于数据......
  • 基于SpringBoot+Vue+uniapp的横向课题信息管理系统的详细设计和实现(源码+lw+部署文档
    文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言......
  • 基于Java+SpringBoot+Vue的电竞交互管理系统设计与实现(源码+lw+部署文档+讲解等)
    文章目录前言项目运行截图技术框架后端采用SpringBoot框架前端框架Vue可行性分析系统测试系统测试的目的系统功能测试数据库表设计代码参考数据库脚本为什么选择我?获取源码前言......
  • SpringSecurity
    1.认证授权的概述1.1什么是认证?进入移动互联网时代,大家每天都在刷手机,常用的软件有微信、支付宝、头条,抖音等,下边拿微信来举例子说明认证相关的基本概念,在初次使用微信前需要注册成为微信用户,然后输入账号和密码即可登录微信,==输入账号和密码登录微信的过程就是认证==。系统......
  • Java/SpringCloud/RabbitMq/无感实现消息携带用户信息 --- 逻辑讲解、代码实现、图形
    一、需求:依据黑马商城hmall为例,用户下单创建订单后,交易服务trade-service向交换机topic发送消息,交换机topic路由到队列,购物车服务cart-service监听此队列,实现自动清空购物车。改造下单功能,将基于OpenFeign的清理购物车同步调用,改为基于RabbitMQ的异步通知:定义t......
  • Spring学习(四)三级缓存
    至此,总结一下三级缓存:singletonObjects:缓存经过了完整生命周期的beanearlySingletonObjects:缓存未经过完整生命周期的bean,如果某个bean出现了循环依赖,就会提前把这个暂时未经过完整生命周期的bean放入earlySingletonObjects中,这个bean如果要经过AOP,那么就会把代理对象放入early......
  • SpringBoot+Vue物流快递仓库管理系统-附源码与配套论文
    1.1研究背景 随着网络不断的普及发展,物流快递仓库管理系统依靠网络技术的支持得到了快速的发展,首先要从员工的实际需求出发,通过了解员工的需求开发出具有针对性的首页、个人中心、员工管理、客户信息管理、驾驶员管理、仓库管理、配送管理、运输管理管理等功能,利用目前网络给......
  • 通过 GraalVM 在 Spring Boot 项目中运行 Python 脚本(强化学习)
    我想要完成的是通过GraalVM在SpringBoot项目中运行python脚本(在我的例子中是agent.py)。我已经安装了GraalVM(cejdk21)并给它一个路径。还在项目结构中定义并根据graalvm和graalvm的python更改了pom.xml。即使它给出了无法找到火炬模块的错误。我还有一个安装了......
  • spring整合Sa-token+gateway实现微信无业务关联登录
    1、RBAC是什么?Role-BasedAccessControl,中文意思是:基于角色(Role)的访问控制。这是一种广泛应用于计算机系统和网络安全领域的访问控制模型。简单来说,就是通过将权限分配给➡角色,再将角色分配给➡用户,来实现对系统资源的访问控制。一个用户拥有若干角色,每一个角色拥有若干权限。这......