SpringCloud源码探析(十二)-基于SpringBoot开发自定义中间件
1.概述
中间件是一种介于操作系统和应用软件之间,为应用软件提供服务功能的软件,按功能划分有消息中间件(Kafka、RocketMQ)、通信中间件(RPC通信中间件,dubbo等),应用服务器等。中间件屏蔽了底层操作系统的复杂性,让开放工程师可以把更多的专注力放在业务系统上,能够有效提高开发人员效率。本文主要分析利用springboot开发自定义日志中间件,通过此中间件能够打印请求入参及返回结果,帮助大家更好地理解利用springboot如何开发中间件。
2.自定义AOP日志中间件
利用springboot开发中间件主要包含以下几个步骤:
1.创建自定义的starter项目
2.定义Starter需要的配置类
3.编写业务功能
4.编写自动配置类
5.编写spring.factories文件加载自动配置类
6.打包安装
本文将会按照上述步骤,以自定义AOP日志中间件为例进行分析。
2.1 需求背景
在利用spring开发的web应用中,请求会从controller进入并经过多次流转,最后返回结果。在这过程中可能会打印大量日志,进行问题排查时需要耗费大量时间和精力,为了能够提升排查问题效率,可以将每一次的请求进入和结束进行标识,打印请求IP、入参以及返回结果,这样在排查问题时能够快速定位请求内容及结果。
所以,基于上述背景,开发一个利用AOP对于入口Controller文件进行拦截处理,打印入参及返回结果等信息,所有利用spring开发的web应用能够直接引用此中间件,直接实现入口日志打印。
2.2 方案设计
整体设计方案如下图所示:

上述设计图主要包括以下内容:
1.SpringBoot Starter 的实现会自动加载配置,通过配置文件确定是否生成SpringAopLogAspect Bean;
2.在SpringAopLogAspect定义切面进行入口日志打印输出。
2.3 代码实现
spring-aop-log-starter类图关系如下图所示:
- AopLogProperties:属性配置类,获取日志打印开关属性,若为true,开启打印;
- AopLogConfig:配置类,依赖AopLogProperties确定是否生成SpringAopLogAspect;
- SpringAopLogAspect:业务逻辑类,拦截Controller并进行日志打印。
2.3.1 pom文件
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><classifier>exec</classifier></configuration></plugin></plugins></build>
2.3.2 AopLogProperties
import org.springframework.boot.context.properties.ConfigurationProperties;/*** @Author: Marinc* @CreateTime: 2023-12-18 14:29* @Description: TODO* @Version: 1.0*/
@ConfigurationProperties(prefix = "aop.log")
public class AopLogProperties {private boolean enable;public AopLogProperties() {}public boolean isEnable() {return enable;}public void setEnable(boolean enable) {this.enable = enable;}}
@ConfigurationProperties,用于创建指定前缀( prefix = “aop.log”)的自定义配置信息,这样就在 yml 或者 properties 中读取到我们自己设定的配置信息。
2.3.3 AopLogConfig
import com.eckey.lab.aop.SpringAopLogAspect;
import com.eckey.lab.properties.AopLogProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @Author: Marinc* @CreateTime: 2023-12-18 15:16* @Description: TODO* @Version: 1.0*/
@Configuration
@EnableConfigurationProperties({AopLogProperties.class})
@ConditionalOnProperty(prefix = "aop.log", value = "enable", havingValue = "true")
public class AopLogConfig {@Bean@ConditionalOnMissingBeanpublic SpringAopLogAspect springLogAspect() {return new SpringAopLogAspect();}}
@Configuration是定义一个配置类;
@EnableConfigurationProperties({AopLogProperties.class})注解的作用是让@ConfigurationProperties注解生效,如果只配置@ConfigurationProperties注解,在IOC容器中是获取不到properties配置文件转化的bean的;
@ConditionalOnProperty(prefix = “aop.log”,value = “enable”,havingValue = “true”)会将配置文件中的值和havingValue的值对比,如果一样则加载Bean;
@ConditionalOnMissingBean仅仅在当前上下文中不存在某个对象时,才会实例化一个 Bean。
2.3.4 SpringAopLogAspect
import com.eckey.lab.utils.IpInfoUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;/*** @Author: Marinc* @CreateTime: 2023-12-18 14:33* @Description: TODO* @Version: 1.0*/
@Slf4j
@Aspect
@Component
public class SpringAopLogAspect {@Autowiredprivate IpInfoUtil ipInfoUtil;@Pointcut("execution(* *..*Controller.*(..))")public void springAopLog(){}@Before("springAopLog()")public void doBefore(JoinPoint joinPoint) throws Throwable {// 接收到请求,记录请求内容ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = attributes.getRequest();log.info("------------------请求开始------------------");// 记录下请求内容log.info("请求路径:{}", request.getRequestURL().toString());log.info("客户端IP :{}" , ipInfoUtil.getIpAddr(request));log.info("参数值 :{}", Arrays.toString(joinPoint.getArgs()));}@AfterReturning(returning = "res", pointcut = "springAopLog()")public void doAfterReturning(Object res) throws Throwable {// 处理完请求,返回内容log.info("返回值 : {}" , res);log.info("------------------请求结束------------------");}}
注解@Aspect定义类为切面类;
@Component 注解,将类生成为 Bean对象;
@Pointcut(“execution(* *…Controller.(…))”),定义切点。在Pointcut中提供了多种切点寻找方式(指定方法名称、范围筛选表达式、自定义注解等),一般在中间件开发中,自定义注解的使用比较多;
@Before(“springAopLog()”),可以理解为是对方法增强的织入动作,在方法执行前先执行;
@AfterReturning(returning = “res”, pointcut = “springAopLog()”)被代理的方法执行完成之后要执行的代码。
2.3.4 spring.factories
1.在resources下新建META-INF文件夹,然后创建spring.factories文件
2.在该文件中加入如下配置,该配置指定上步骤中定义的配置类为自动装配的配置
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.eckey.lab.config.AopLogConfig
2.3.5 测试结果
1.引入pom
<dependency><groupId>com.eckey.lab</groupId><artifactId>spring-aop-log-starter</artifactId><version>1.0-SNAPSHOT</version></dependency>
2.在properties中配置
#配置切面打印日志
aop.log.enable=true
3.测试验证
在订单服务中访问地址:http://127.0.0.1:8082/order/test,结果如下:


3.小结
1.本文初步分析了一个基于切面和SpringBoot结合开发的中间件,包括了自定义配置如何设置、SpringBoot如何加载和生成Bean,以及切面拦截后的处理;
2.在切面拦截的逻辑相对比较简单,仅仅时拦截并打印了一些信息,这里可以进行拓展一下,通过自定义注解,配置在需要统计的方法上,统计一些关键信息,进行统计汇总,具体可以看第4节参考文献进行发散;
3.基于springboot开发中间件是一项基本技能,可以基于自己日常中常用的场景(短信发送、邮件发送等),基于不同场景多动手实践。
4.参考文献
1.https://blog.csdn.net/qq_33479841/article/details/116306864
2.https://zhuanlan.zhihu.com/p/642035645
5.附录
1.https://gitee.com/Marinc/nacos/tree/master/spring-aop-log-starter
相关文章:
SpringCloud源码探析(十二)-基于SpringBoot开发自定义中间件
1.概述 中间件是一种介于操作系统和应用软件之间,为应用软件提供服务功能的软件,按功能划分有消息中间件(Kafka、RocketMQ)、通信中间件(RPC通信中间件,dubbo等),应用服务器等。中间…...
基于CNN+数据增强+残差网络Resnet50的少样本高准确度猫咪种类识别—深度学习算法应用(含全部工程源码)+数据集+模型(一)
系列文章目录 基于CNN数据增强残差网络Resnet50的少样本高准确度猫咪种类识别—深度学习算法应用(含全部工程源码)数据集模型(一) 基于CNN数据增强残差网络Resnet50的少样本高准确度猫咪种类识别—深度学习算法应用(含全部工程源码)数据集模型…...
python实现贪吃蛇游戏
文章目录 1、项目说明2、项目预览3、开发必备4、贪吃蛇代码实现4.1、窗口和基本参数实现4.2、绘制背景4.3、绘制墙壁4.4、绘制贪吃蛇4.5、绘制食物4.6、实现长度信息显示4.7、定义游戏暂停界面4.8、定义贪吃蛇死亡界面4.9、实现贪吃蛇碰撞效果4.10、实现添加食物功能4.11、实现…...
ios备忘录怎么导入华为 方法介绍
作为一个常常需要在不同设备间切换的人,我深知备忘录的重要性。那些突如其来的灵感、重要的会议提醒、甚至是生活中的琐碎小事,我们都习惯性地记录在备忘录里。但当我决定从iPhone转向华为时,一个问题困扰了我:如何将那些珍贵的备…...
electron与cesium组件入门应用功能
electron与cesium组件入门应用功能 运行应用效果图: electron应用目录,需要包括三个文件: index.html main.js package.json (一)、创建一个新项目 目录名称:project_helloWolrd (二)、生成package.json文件 npm init --yes(三&#x…...
Jenkins Docker Cloud在Linux应用开发CI中的实践
Jenkins Docker Cloud在Linux应用开发CI中的实践 背景 通过代码提交自动触发CI自动构建、编译、打包是任何软件开发组织必不可少的基建,可以最大程度保证产物的一致性,方便跨组跨部门协作,代码MR等。 Docker在流水线中越来越重要ÿ…...
502 Bad Gateway with nginx + apache + subversion + ssl
svn commit的时候返回 unexpected http status 502 bad gateway on解决方法,参考:https://stackoverflow.com/questions/2479346/502-bad-gateway-with-nginx-apache-subversion-ssl-svn-copy 在nginx中代理svn中添加 location /svn {set $fixed_dest…...
【PostgreSQL内核学习(十八)—— 存储管理(存储管理的体系结构)】
存储管理 概述存储管理器的体系结构存储管理器的主要任务读写元组过程 声明:本文的部分内容参考了他人的文章。在编写过程中,我们尊重他人的知识产权和学术成果,力求遵循合理使用原则,并在适用的情况下注明引用来源。 本文主要参考…...
Android的组件、布局学习
介绍 公司组织架构调整,项目组需要承接其他项目组的android项目,负责维护和开发新需求,故学习下基础语法和项目开发。 组件学习 Toolbarheader布局部分 就是app最顶部的部分 他的显示与否,是与F:\androidProject\android_lear…...
【离散数学】——期末刷题题库(树其一)
🎃个人专栏: 🐬 算法设计与分析:算法设计与分析_IT闫的博客-CSDN博客 🐳Java基础:Java基础_IT闫的博客-CSDN博客 🐋c语言:c语言_IT闫的博客-CSDN博客 🐟MySQL:…...
光模块市场分析与发展趋势预测
光模块是光通信领域的重要组成部分,随着数字经济,大数据,云计算,人工智能等行业的兴起,光模块市场经历了快速发展,逐渐在数据中心、无线回传、电信传输等应用场景中得到广泛应用。本文将基于当前光模块全球…...
Python轴承故障诊断 (八)基于EMD-CNN-GRU并行模型的故障分类
目录 前言 1 经验模态分解EMD的Python示例 2 轴承故障数据的预处理 2.1 导入数据 2.2 制作数据集和对应标签 2.3 故障数据的EMD分解可视化 2.4 故障数据的EMD分解预处理 3 基于EMD-CNN-GRU并行模型的轴承故障诊断分类 3.1 训练数据、测试数据分组,数据分ba…...
鸿蒙实现年月日十分选择框,支持年月日、月日、日、年月日时分、时分切换
import DateTimeUtils from ./DateTimeUtils;CustomDialog export default struct RQPickerDialog {controller: CustomDialogControllertitle: string 这是标题TAG: string RQPickerDialog// 0 - 日期类型(年月日) 1 - 时间类型(时分&a…...
IntelliJ IDE 插件开发 | (三)消息通知与事件监听
系列文章 IntelliJ IDE 插件开发 |(一)快速入门IntelliJ IDE 插件开发 |(二)UI 界面与数据持久化IntelliJ IDE 插件开发 |(三)消息通知与事件监听 前言 在前两篇文章中讲解了关于插件开发的基础知识&…...
VUE小知识点
Vue 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面。 Vue 的主要作用是帮助开发者构建现代 Web 应用程序。它允许前端开发人员专注于应用程序…...
深入了解常见的应用层网络协议
目录 1. HTTP协议 1.1. 工作原理 1.2. 应用场景 1.3. 安全性考虑 2. SMTP协议 2.1. 工作原理 2.2. 应用场景 2.3. 安全性考虑 3. FTP协议 3.1. 工作原理 3.2. 应用场景 3.3. 安全性考虑 4. DNS协议 4.1. 工作原理 4.2. 应用场景 4.3. 安全性考虑 5. 安全性考虑…...
网络爬虫 多任务采集
一、JSON文件存储 JSON,全称为 JavaScript 0bject Notation,也就是JavaSript 对象标记,它通过对象和数组的组合来表示数据,构造简洁但是结构化程度非常高,是一种轻量级的数据交换格式。本节中,我们就来了解如何利用 P…...
真实并发编程问题-1.钉钉面试题
👏作者简介:大家好,我是爱吃芝士的土豆倪,24届校招生Java选手,很高兴认识大家📕系列专栏:Spring源码、JUC源码、Kafka原理、分布式技术原理、数据库技术🔥如果感觉博主的文章还不错的…...
基于vue+element-plus+echarts制作动态绘图页面(柱状图,饼图和折线图)
前言 我们知道echarts是一个非常强大的绘图库,基于这个库,我们可以绘制出精美的图表。对于一张图来说,其实比较重要的就是配置项,填入不同的配置内容就可以呈现出不同的效果。 当然配置项中除了样式之外,最重要的就是…...
2312llvm,02前端
前端 编译器前端,在生成目标相关代码前,把源码变换为编译器的中间表示.因为语言有独特语法和语义,所以一般,前端只处理一个语言或一组类似语言. 比如Clang,处理C,C,objective-C源码. 介绍Clang Clang项目是C,C,Objective-C官方的LLVM前端.Clang的官方网站在此. 实际编译器(…...
AI驱动编辑预设:智能调色与音频处理实战指南
1. 项目概述:AI驱动的编辑预设库最近在折腾视频和图片后期的时候,发现一个挺有意思的项目,叫kaushalrao/ai-editor-presets。光看名字,你可能觉得这又是一个普通的滤镜包或者调色预设合集。但深入用下来,我发现它的核心…...
蕲艾壹号模式开发介绍(代码)
以下是关于蕲艾壹号模式开发的介绍和代码示例:蕲艾壹号模式开发介绍蕲艾壹号通常指基于蕲艾(一种中药材)相关产品的电商或健康管理平台。开发模式可能包含以下核心模块:电商功能模块 商品展示、购物车、订单管理、支付接口集成&am…...
OpenFold实战指南:在Linux系统部署蛋白质结构预测模型
1. 从仰望到上手:OpenFold如何让蛋白质结构预测走进寻常实验室去年AlphaFold2横空出世,几乎以一己之力解决了困扰生物学界半个世纪的“蛋白质折叠问题”,其意义不亚于在生命科学领域投下了一颗重磅炸弹。一时间,无论是结构生物学家…...
Arm架构在中国市场的潜力与挑战:从技术选型到实践落地
1. 项目概述:从一次技术选型引发的深度思考最近在为一个边缘计算项目做硬件选型,团队里关于采用x86还是Arm架构的服务器争论了好几天。这让我想起,这几年在国内的云计算、数据中心、甚至个人消费电子领域,Arm架构的声音是越来越响…...
朋升爱生活
我爱生活。...
龙虾热降温,我们到底需要什么样的 Agent?
责编 | 《AI 进化论》栏目组出品 | CSDN(ID:CSDNnews)过去几个月,AI Agent 无疑是技术圈最火热的词。我们聊颠覆、聊入口、聊取代……仿佛一夜之间,一个无所不能的“数字员工”就能接管我们的一切工作。热度之下&#…...
三步快速解锁网盘高速下载:LinkSwift直链解析终极指南
三步快速解锁网盘高速下载:LinkSwift直链解析终极指南 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼…...
Jetson AGX Orin到手后,第一件事不是装CUDA,而是先搞定这个源(附nvidia-l4t-apt-source.list配置)
Jetson AGX Orin开发板开箱必做:正确配置软件源的深度指南 当你第一次拿到Jetson AGX Orin这款强大的边缘计算设备时,兴奋之余可能会迫不及待地想要安装CUDA、cuDNN等AI开发环境。但很多开发者都会在这里踩到一个"坑"——直接运行sudo apt ins…...
Publify SEO优化完全指南:提升博客排名的7个关键策略
Publify SEO优化完全指南:提升博客排名的7个关键策略 【免费下载链接】publify A self hosted Web publishing platform on Rails. 项目地址: https://gitcode.com/gh_mirrors/pu/publify Publify是一款基于Ruby on Rails的自托管Web发布平台,也是…...
Claude与Figma智能协作:基于MCP协议的设计自动化实践
1. 项目概述:当Claude遇上Figma,设计协作的智能革命如果你是一名产品设计师或前端工程师,大概率经历过这样的场景:在Figma里反复调整一个组件的间距,只为找到那个“感觉对了”的数值;或者为了统一整个项目的…...
