Spring Boot 实现 AOP 动态热插拔功能并附DEMO源码

发布于:2024-07-05 ⋅ 阅读:(16) ⋅ 点赞:(0)

在这里插入图片描述

😄 19年之后由于某些原因断更了三年,23年重新扬帆起航,推出更多优质博文,希望大家多多支持~
🌷 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志
🎐 个人CSND主页——Micro麦可乐的博客
🐥《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程,入门到实战
🌺《RabbitMQ》专栏主要介绍使用JAVA开发RabbitMQ的系列教程,从基础知识到项目实战
🌸《设计模式》专栏以实际的生活场景为案例进行讲解,让大家对设计模式有一个更清晰的理解
💕《Jenkins实战》专栏主要介绍Jenkins+Docker的实战教程,让你快速掌握项目CI/CD,是2024年最新的实战教程
🌞《Spring Boot》专栏主要介绍我们日常工作项目中经常应用到的功能以及技巧,代码样例完整
如果文章能够给大家带来一定的帮助!欢迎关注、评论互动~

前言

本文对应代码下载地址:https://download.csdn.net/download/lhmyy521125/89504659 无需积分!

AOP(面向切面编程)是一种强大的编程范式,可以用于日志记录性能监控安全检查等跨越多个模块的通用功能。实现 AOP 的动态热插拔可以让我们在不重启应用的情况下启用禁用特定的切面,提高系统的灵活性和可维护性。

我们以一个例子来说明一下为什么需要 AOP 动态热插拔:我们系统有一个 AOP 切面,它负责了记录用户传递参数、执行时间、接口返回结果,默认是不开启的,现在因为某些原因需要检测某个接口参数接收情况 + 耗时 + 返回数据,那么我们就需要在不重启应用的情况下,动态开启关闭AOP切面来达到我们想要的效果。

本文就跟着博主一起来学习在 Spring Boot 中实现 AOP 的动态热插拔功能。


应用场景

动态热插拔功能适用的场景有很多,这里简单举例几个场景:

  • 1、调试和排查问题:在生产环境中临时启用日志或性能监控切面,以便快速定位问题。例如,当发现某个服务的响应时间突然增加时,可以动态启用性能监控切面,记录每个方法的执行时间,从而找出性能瓶颈。

  • 2、动态功能开关:根据业务需求动态启用或禁用某些功能,如限流鉴权等。例如,在高流量的促销活动期间,可以临时启用限流切面,防止服务器过载。在活动结束后,可以动态关闭限流切面,恢复正常流量处理。

  • 3、性能优化:在高负载时关闭一些耗性能的切面以提高系统吞吐量。例如,在系统的非高峰期,可以启用详细的日志记录和审计切面,以便收集用户行为数据和系统操作日志。而在系统高峰期,可以临时关闭这些切面,以减少日志记录带来的性能开销。

  • 4、安全审计:在面对安全审计或合规检查时,可以临时启用安全检查切面,记录所有的安全相关操作。例如,在接到安全审计通知时,可以动态启用安全检查切面,记录所有用户的登录和数据访问行为,确保审计数据的完整性。

  • 5、实验和AB测试:在进行新功能的实验和AB测试时,可以动态控制某些功能的启用。例如,在推出新功能时,可以动态启用或禁用相关切面,控制新功能的实验组和对照组,从而评估新功能的效果和性能影响。


开始实战

废话了那么多,我们还是以代码样例来进行演示讲解

❶ 初始化项目

首先,创建一个新的 Spring Boot 项目,在在 pom.xml 文件中添加相关依赖

<dependencies>
    <!-- Spring Boot Starter Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- Spring Boot Starter AOP -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
</dependencies>

❷ 创建自定义注解

package com.toher.project.dynamic;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Loggable {
}

❸ 定义配置管理类

定义一个配置管理类,主要作用是控制AOP开关

package com.toher.project.dynamic;

import org.springframework.stereotype.Component;

@Component
public class AspectConfig {

    private boolean loggingEnabled = true;

    public boolean isLoggingEnabled() {
        return loggingEnabled;
    }

    public void setLoggingEnabled(boolean loggingEnabled) {
        this.loggingEnabled = loggingEnabled;
    }
}

❹ 定义切面类

定义一个切面类,模拟业务耗时打印的功能

package com.toher.project.dynamic;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

    @Autowired
    private AspectConfig aspectConfig;

    @Around("@annotation(com.toher.project.dynamic.Loggable)")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
        if (!aspectConfig.isLoggingEnabled()) {
            return joinPoint.proceed();
        }
        long start = System.currentTimeMillis();
        Object proceed = joinPoint.proceed();
        long executionTime = System.currentTimeMillis() - start;
        System.out.println(joinPoint.getSignature() + " 方法执行时间 " + executionTime + "ms");
        return proceed;
    }
}

❺ 使用切面

编写一个 service,在需要记录日志的方法上使用 @Loggable 注解

package com.toher.project.dynamic;

import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Loggable
    public void performOperation() {
        // 业务逻辑
        System.out.println("执行相关操作...");
    }
}

❻ 创建测试Controller

接下来编写一个Controller主要用于测试,开关AOP的日志时间打印功能

package com.toher.project.dynamic;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/config")
public class ConfigController {

    @Autowired
    private AspectConfig aspectConfig;

    @Autowired
    private UserService userService;

    /**
     * 测试AOP执行
     * @return
     */
    @GetMapping("/logging")
    public String isLoggingEnabled() {
        userService.performOperation();
        return "SUCCESS 当前loggingEnabled为 " + aspectConfig.isLoggingEnabled();
    }

    /**
     * 开关AOP日志耗时记录功能
     * @param enabled
     */
    @PostMapping("/logging")
    public String setLoggingEnabled(@RequestParam boolean enabled) {
        aspectConfig.setLoggingEnabled(enabled);
        return "更新成功当前loggingEnabled为 " + aspectConfig.isLoggingEnabled();
    }
}

❼ 测试效果

运行Spring Boot项目,博主使用 Apifox 访问 http://localhost:端口号/api/config/logging
在这里插入图片描述
观察控制台输出

在这里插入图片描述

修改我们的loggingEnabled
在这里插入图片描述
修改后再次观察控制台,发现当 loggingEnabled = false 本次并没有执行耗时打印功能

在这里插入图片描述


总结

通过上述简单的DEMO相信大家已经初步了解了实现 AOP 动态热插拔功能,DEMO代码仅仅为了演示,实际上我们项目中还可以考虑以下几点:

  • 配置持久化:可以将配置状态存储在数据库或其他持久化存储中,确保应用重启后配置不丢失。
  • 丰富的控制接口:根据实际需求,可以扩展 REST 接口,增加对多个切面和更多配置项的管理。
  • 细粒度控制:在切面逻辑中可以根据更多条件(如请求参数、用户角色等)进行更细粒度的控制。

本篇文章我们实现了 Spring Boot 项目中 AOP 切面的动态热插拔功能。关键点在于通过配置管理类动态控制切面的启用状态,并在切面逻辑中根据状态决定是否执行切面代码。这样可以在不重启应用的情况下动态调整应用行为,提高系统的灵活性和可维护性。

如果本文对您有所帮助,希望 一键三连 给博主一点点鼓励,如果您有任何疑问或建议,请随时留言讨论!


在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到