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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/220850.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

什么是 DDoS ?如何识别DDoS?怎么应对DDOS攻击

什么是DDOS攻击 DDoS攻击&#xff08;Distributed Denial of Service Attack&#xff09;即分布式拒绝服务攻击&#xff0c;是一种利用分布式网络来发起大量的请求&#xff0c;占用目标服务器或网络资源的攻击行为。这种攻击方式可以瘫痪目标系统&#xff0c;导致其无法正常提供…

每日一题,二维平面

给你 二维 平面上两个 由直线构成且边与坐标轴平行/垂直 的矩形&#xff0c;请你计算并返回两个矩形覆盖的总面积。 每个矩形由其 左下 顶点和 右上 顶点坐标表示&#xff1a; 第一个矩形由其左下顶点 (ax1, ay1) 和右上顶点 (ax2, ay2) 定义。 第二个矩形由其左下顶点 (bx1, …

vscode颜色主题插件one dark Pro安装

1.点击扩展图标→搜索“one dark Pro”→第一个点击安装 2.安装成功后&#xff0c;不要忘了点击设置颜色主题 3.看下效果&#xff1a;

如何获取光标在 textarea 中的位置

如何获取光标在 textarea 中的位置 这里的位置不是指光标所在的字符数位置&#xff0c;而是相对 textarea 的向上向左的大体像素位置。 你可以通过 textarea.selectionStart() 来获取光标在 textarea 文本中的字符位置&#xff0c;比如在第几个字符上。 一、如何获取大体的像…

YOLOv5改进 | 注意力篇 | DiverseBranchBlock(DBB)多元分支模块(有效涨点)

一、本文介绍 本文带来的改进机制是YOLOv5模型与多元分支模块&#xff08;Diverse Branch Block&#xff09;的结合&#xff0c;Diverse Branch Block (DBB) 是一种用于增强卷积神经网络性能的结构重新参数化技术。这种技术的核心在于结合多样化的分支&#xff0c;这些分支具有…

eclipse中基于maven构建的web项目pom.xml中指定的jar包无法发布到tomcat中

eclipse运行maven web项目报错&#xff1a; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 信息: Star…

vp与vs联合开发-通过FrameGrabber连接相机

添加控件 1.CogRecordDisplay 控件 用于显示图像 初始化相机对象方法 //启动窗体时 调用初始化相机方法 //封装相机关闭方法 //窗体关闭时 调用相机关闭方法 拍照 设置采图事件 // 保存图像 设置曝光按钮事件 1.可变参数

C++刷题 -- KMP算法

C刷题 – KMP算法 文章目录 C刷题 -- KMP算法1.算法讲解2.算法实现 https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/description/ 1.算法讲解 KMP算法是一种字符串匹配算法&#xff0c;当出现字符串不匹配时&#xff0c;可以记录一部分之…

2024 年 8 个顶级开源 LLM(大语言模型)

如果没有所谓的大型语言模型&#xff08;LLM&#xff09;&#xff0c;当前的生成式人工智能革命就不可能实现。LLM 基于 transformers&#xff08;一种强大的神经架构&#xff09;是用于建模和处理人类语言的 AI 系统。它们之所以被称为“大”&#xff0c;是因为它们有数亿甚至…

Python tkinter 初探Toplevel控件搭建父子窗口

目录 Toplevel控件搭建父子窗口 最简明的父子窗口框架 改进一&#xff1a;屏蔽和开放按钮 改进二&#xff1a;子窗口始终在主窗口之上 改进三&#xff1a;增加子窗口的关闭协议 改进四&#xff1a;使子窗口长获焦点 总结 Toplevel控件搭建父子窗口 最近&#xff0c;用P…

EasyExcel合并相同内容单元格及动态标题功能的实现

一、最初版本 导出的结果&#xff1a; 对应实体类代码&#xff1a; import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.write.style.ColumnWidth; import com.alibaba.excel.annotation.write.style.ContentLoopMerge; import com.al…

【TB作品】51单片机,具有报时报温功能的电子钟

2.具有报时报温功能的电子钟 一、功能要求: 1.显示室温。 2.具有实时时间显示。 3.具有实时年月日显示和校对功能。 4.具有整点语音播报时间和温度功能。 5.定闹功能,闹钟音乐可选。 6.操作简单、界面友好。 二、设计建议: 1.单片机自选(C51、STM32或其他单片机)。 2.时钟日历芯…

第十七章 爬虫scrapy登录与中间件2

文章目录 数据盘区太快会报错&#xff0c;setting中配置延迟 连接提取器

深度学习记录--矩阵维数

如何识别矩阵的维数 如下图 矩阵的行列数容易在前向和后向传播过程中弄错&#xff0c;故写这篇文章来提醒易错点 顺便起到日后查表改错的作用 本文仅作本人查询参考(摘自吴恩达深度学习笔记)

线上环境如何正确配置 Django 的 DEBUG?

Author&#xff1a;rab Django Version&#xff1a;3.2 Python Version&#xff1a;3.9 目录 前言一、DEBUG True二、DEBUG False三、页面异常解决总结 前言 由于最近在学习 Django 的知识&#xff0c;于是尝试开发了一套 Blog 系统&#xff0c;在本地测试时是页面显示没问题…

Windows 10如何关闭系统自动更新(实用教程)

本章教程&#xff0c;用最简洁的方式介绍在windows10中如何关闭系统自动更新。 目录 一、关闭自动更新服务 二、关闭自动更新组策略 一、关闭自动更新服务 1、 winr 2、services.msc 3、找到并双击 Windows Update 修改启动类型为禁用 二、关闭自动更新组策略 1、winr 2、gp…

el-form与el-upload结合上传带附件的表单数据(前端篇)

1.写在之前 本文前端采用Vue element-plus技术栈&#xff0c;前端项目参考yudao-ui-admin-vue3项目与Geeker-Admin项目。 这篇文章是el-form与el-upload结合上传带附件的表单数据&#xff08;后端篇&#xff09;-CSDN博客姐妹篇&#xff0c;后端篇文章主要讲的是后端的实现逻…

JavaEE:线程池精讲

目录 一.什么是线程池 二.线程池的实现原理 &#x1f388;为什么要有工厂模式&#xff1f; 三.线程池的构造方法解读 &#x1f388;线程池的拒绝策略 四.自己实现一个线程池 一.什么是线程池 简单来说&#xff0c;线程池就好比一块鱼塘&#xff0c;鱼塘中的每条鱼就是一个线程…

SQL注入绕过正则及无列名注入

渗透测试 一、select\b[\s\S]*\bfrom正则二、科学计数法绕过三、过滤information四、无列名注入1、利用 join-using 注列名。2、无列名查询 五、报错注入7大常用函数1.ST_LatFromGeoHash()&#xff08;mysql>5.7.x&#xff09;payload 2.ST_LongFromGeoHash&#xff08;mysq…

针对这两个趋势,3.0全新新零售商业模式可以采取以下策略:

国内市场确实存在“消费升级”和“消费降级”两个趋势&#xff0c;这是由于不同消费者群体的需求和购买力存在差异。消费升级主要发生在高端市场&#xff0c;消费者愿意为高品质、高价值、高价格的商品和服务付出更多。而消费降级则主要发生在中低端市场&#xff0c;消费者更加…