Spring Boot中AOP日志序列化问题解决方案

spring boot中, package com.weiyu.model; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * 文件数据 */ @Data @AllArgsConstructor @NoArgsConstructor public class FileData { private String fileName; @JsonIgnore // 防止序列化到日志,是一个双向忽略的注解,就是接收和发送参数都为null private byte[] fileContent; } package com.weiyu.aop; import com.alibaba.fastjson.JSONObject; import com.weiyu.mapper.PerformanceLogMapper; import com.weiyu.model.PerformanceLog; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.time.LocalDateTime; import java.util.Arrays; /** * 时间AOP类(时间切面类) */ @Component // 将当前类 TimeAspect 交给 Spring IOC 容器管理 @Aspect // 当前类 TimeAspect 为AOP类(切面类) @Slf4j public class TimeAspect { @Autowired private PerformanceLogMapper performanceLogMapper; /** * 切面:计算执行耗时 * @param joinPoint 固定参数 ProceedingJoinPoint joinPoint(API调用) * @return 原始方法运行的返回值 Object * @throws Throwable 异常 */ // @Before 前置通知,在目标方法前被执行 // @After 后置通知,在目标方法后被执行 // @Around 环绕通知,在目标方法前、后都被执行 // @Around("execution(* com.weiyu.service.*.*(..))") // 切入点表达式,com.weiyu.service 这个包下的所有类和接口的所有方法都会切入执行 // @Around("execution(* com.weiyu.service.impl.PrintServiceImpl.*(..))") // 切入点表达式,com.weiyu.service.impl.PrintServiceImpl 这个类下的所有方法都会切入执行 /* 切入点表达式: 使用 || 组合多个条件 com.weiyu.service.impl.PrintServiceImpl 这个类下的所有方法 或者 com.weiyu.service.impl.ReportServiceImpl 这个类下的所有以query开头的方法 或者 com.weiyu.service.impl.JJDServiceImpl 这个类下的所有以query开头的、返回值类型为PageBean的、参数类型为JJDQueryDTO的方法 com.weiyu.mapper 这个包下的所有类和接口 都会切入执行 通配符: *: 匹配任意字符(除包分隔符 .) ..:匹配当前包及其子包,或任意数量的参数 */ @Around("execution(* com.weiyu.service.impl.PrintServiceImpl.*(..)) || " + "execution(* com.weiyu.service.impl.ReportServiceImpl.query*(..)) || " + "execution(com.weiyu.pojo.PageBean com.weiyu.service.impl.JJDServiceImpl.query*(com.weiyu.pojo.JJDQueryDTO))") public Object calculateExecuteTime(ProceedingJoinPoint joinPoint) throws Throwable { // 记录方法执行的开始时间 long beginTime = System.currentTimeMillis(); // 调用原始方法运行 Object result = joinPoint.proceed(); // 记录方法执行的结束时间 long endTime = System.currentTimeMillis(); // 计算执行耗时,单位ms long executeTime = endTime - beginTime; // 输出到日志,包含返回类型、类名、方法名、执行耗时 log.info("{} 执行时间:{} ms", joinPoint.getSignature(), executeTime); // 返回原始方法运行的返回值 return result; } /** * 切面:计算sql执行耗时,定位慢sql * @param joinPoint 固定参数 ProceedingJoinPoint joinPoint(API调用) * @return 原始方法运行的返回值 Object * @throws Throwable 异常 */ @Around("execution(* com.weiyu.mapper.*.*(..))") // 切入点表达式,com.weiyu.mapper 这个包下的所有类和接口都会切入执行 public Object sqlExecutionTimeDuration(ProceedingJoinPoint joinPoint) throws Throwable { // 记录方法执行的开始时间 long beginTime = System.currentTimeMillis(); // 调用原始方法运行 Object result = joinPoint.proceed(); // 记录方法执行的结束时间 long endTime = System.currentTimeMillis(); // 计算执行耗时,单位ms long executionTimeDuration = endTime - beginTime; // 获取方法签名 MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); // 获取包名 String packageName = methodSignature.getDeclaringType().getPackageName(); // 获取类名(简单类名,不带包名) String className = methodSignature.getDeclaringType().getSimpleName(); // 获取方法名 String methodName = methodSignature.getName(); // 获取方法参数类型 Object[] methodParamTypeArgs = methodSignature.getParameterTypes(); String methodParamTypes = Arrays.toString(methodParamTypeArgs); // 获取方法参数名 String[] methodParamNameArgs = methodSignature.getParameterNames(); String methodParamNames = Arrays.toString(methodParamNameArgs); // 获取方法参数值 Object[] methodParamValueArgs = joinPoint.getArgs(); String methodParamValues = Arrays.toString(methodParamValueArgs); // 获取方法返回类型(简单类名,不带包名) String methodReturnType = methodSignature.getReturnType().getSimpleName(); // 执行耗时超过3000ms if (executionTimeDuration > 3000 || "FileData".equals(methodReturnType)) { // 方法返回值 String methodReturnValue = JSONObject.toJSONString(result); // 输出到日志,包含执行耗时、包名、类名、方法名、方法参数类型、方法参数名、方法参数值、方法返回类型、方法返回值 log.info("慢sql>>>执行sql时间:{} ms,包名:{},类名:{},方法名:{},方法参数类型:{},方法参数名:{},方法参数值:{},方法返回类型:{},方法返回值:{}", executionTimeDuration, packageName, className, methodName, methodParamTypes, methodParamNames, methodParamValues, methodReturnType, methodReturnValue); // 性能日志持久化 PerformanceLog performanceLog = new PerformanceLog(); performanceLog.setPerformanceType(1); performanceLog.setOperationTime(LocalDateTime.now()); performanceLog.setPackageName(packageName); performanceLog.setClassName(className); performanceLog.setMethodName(methodName); performanceLog.setMethodParamTypes(methodParamTypes); performanceLog.setMethodParamNames(methodParamNames); performanceLog.setMethodParamValues(methodParamValues); performanceLog.setMethodReturnType(methodReturnType); performanceLog.setMethodReturnValue(methodReturnValue); performanceLog.setExecutionTimeDuration(executionTimeDuration); // 将性能日志存储到数据库(异步执行) performanceLogMapper.insert(performanceLog); } else { log.info("{} 执行sql时间:{} ms", joinPoint.getSignature(), executionTimeDuration); } // 返回原始方法运行的返回值 return result; } } 为什么这样还会输出: 2026-01-17T12:44:24.310+08:00 INFO 12652 --- [http-nio-8080-exec-1] com.weiyu.aop.TimeAspect : 慢sql>>>执行sql时间:145 ms,包名:com.weiyu.mapper,类名:WorkInstructionMapper,方法名:selectFileData,方法参数类型:[class java.lang.String],方法参数名:[fileNo],方法参数值:[4-5-6],方法返回类型:FileData,方法返回值:{"fileContent":"JVBERi0xLjcNCiW1tbW1DQoxIDAgb2JqDQo8PC9UeXBlL0NhdGFsb2cvUGFnZXMgMiAwIFIvTGFuZyh6aCkgL1N0cnVjdFRyZWVSb290IDI3MyAwIFIvTWFya0luZm88PC9NYXJrZWQgdHJ1ZT4+L01ldGFkYXRhIDE3MTQgMCBSL1ZpZXdlclByZWZlcmVuY2VzIDE3MTUgMCBSPj4NCmVuZG9iag0KMiAwIG9iag0KPDwvVHlwZS9QYWdlcy9Db3VudCA2Ni9LaWRzWyAzIDAgUiAxNiAwIFIgMjAgMCBSIDI0IDAgUiAyOCAwIFIgMzIgMCBSIDM2IDAgUiA0MCAwIFIgNDMgMCBSIDQ3IDAgUiA1MSAwIFIgNTUgMCBSIDU4IDAgUiA2MiAwIFIgNjYgMCBSIDcwIDAgUiA3NCAwIFIgNzggMCBSIDgyIDAgUiA4NiAwIFIgOTAgMCBSIDkyIDAgUiA5NiAwIFIgMTAwIDAgUiAxMDQgMCBSIDEwOCAwIFIgMTEyIDAgUiAx...", "fileName":"操作流程-物资管理.pdf"}

看到你的问题了。问题在于你使用了@JsonIgnore注解来防止fileContent字段被序列化,但是在你自定义的 AOP 切面中,仍然打印出了这个字段的内容。

让我解释一下原因和解决方案:

问题原因

  1. 注解作用域问题

    • @JsonIgnore是 Jackson 的注解,它只在 Jackson 的序列化/反序列化过程中起作用

    • 你在 AOP 切面中使用的是 FastJSON 的JSONObject.toJSONString(result),FastJSON 不识别 Jackson 的注解

  2. 序列化时机

    • 当方法返回FileData对象时,AOP 切面会先执行

    • 切面中的JSONObject.toJSONString(result)会使用 FastJSON 序列化整个对象

    • FastJSON 默认会序列化所有字段,包括byte[] fileContent

解决方案

你有几个选项可以选择:

方案1:修改 AOP 切面,排除大字段

java

// 在 sqlExecutionTimeDuration 方法中,修改序列化逻辑 if (executionTimeDuration > 3000 || "FileData".equals(methodReturnType)) { // 特殊处理 FileData 对象,避免序列化 fileContent String methodReturnValue; if (result instanceof FileData) { FileData fileData = (FileData) result; // 创建一个简化的对象,排除 fileContent Map<String, Object> simplified = new HashMap<>(); simplified.put("fileName", fileData.getFileName()); simplified.put("fileContentSize", fileData.getFileContent() != null ? fileData.getFileContent().length : 0); methodReturnValue = JSONObject.toJSONString(simplified); } else { methodReturnValue = JSONObject.toJSONString(result); } // 后续日志记录... }

方案2:为 FastJSON 添加自定义配置

创建一个自定义的 FastJSON 配置,排除特定字段:

java

@Component public class FastJsonConfig { @PostConstruct public void init() { // 为 FileData 类添加自定义序列化器 ParserConfig.getGlobalInstance().putDeserializer(FileData.class, new ObjectDeserializer() { @Override public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) { return null; } @Override public int getFastMatchToken() { return 0; } }); } }

方案3:使用 Jackson 代替 FastJSON(推荐)

如果你项目中主要使用 Jackson,可以在切面中也使用 Jackson:

java

import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; @Configuration public class JacksonConfig { @Bean public ObjectMapper objectMapper() { ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new JavaTimeModule()); mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); return mapper; } } // 在 TimeAspect 中 @Autowired private ObjectMapper objectMapper; // 修改序列化部分 String methodReturnValue = objectMapper.writeValueAsString(result);

方案4:自定义 FastJSON 的序列化过滤器

java

// 创建过滤器 SerializeFilter filter = new PropertyPreFilter() { @Override public boolean apply(JSONSerializer serializer, Object object, String name) { // 如果是 FileData 对象的 fileContent 字段,则跳过 if (object instanceof FileData && "fileContent".equals(name)) { return false; } return true; } }; // 使用过滤器 String methodReturnValue = JSONObject.toJSONString(result, filter);

方案5:最简单的方法 - 直接跳过 FileData 的返回值

java

// 修改条件判断 if (executionTimeDuration > 3000) { // 如果执行时间超过阈值,才记录日志 // 移除 || "FileData".equals(methodReturnType) 这个条件 // ... } // 或者特殊处理 FileData String methodReturnValue; if (result instanceof FileData) { methodReturnValue = "FileData object with fileContent omitted"; } else { methodReturnValue = JSONObject.toJSONString(result); }

建议

推荐方案1或方案3

  • 方案1简单直接,只修改切面逻辑

  • 方案3更加标准化,统一使用 Jackson 作为序列化工具

这样修改后,你的日志就不会再输出fileContent的二进制内容了,只会记录文件信息(如文件名、文件大小等),既保护了敏感数据,又减少了日志体积。

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

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

相关文章

江苏华大的产品线全吗,与同行相比优势在哪,华大性价比高吗 - 工业品牌热点

2026年化工新材料行业加速向专精特新转型,定制化聚酯多元醇作为聚氨酯产业的核心原料,已成为企业突破同质化内卷、提升产品附加值的关键支撑。无论是适配不同应用场景的细分产品供应,还是全流程研发定制服务,优质服…

spaCy v3.2发布:性能提升与向量新特性

Introducing spaCy v3.2 我们很高兴推出spaCy自然语言处理库的v3.2版本。自v3.1以来&#xff0c;我们增加了自定义训练和评分的可用性改进&#xff0c;提升了在Apple M1和Nvidia GPU硬件上的性能&#xff0c;并支持使用我们的新哈希嵌入扩展floret来实现空间高效的向量。 spa…

实用指南:认识网络空间搜索引擎

实用指南:认识网络空间搜索引擎2026-01-17 13:23 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !import…

全网最全8个一键生成论文工具,本科生轻松搞定论文格式!

全网最全8个一键生成论文工具&#xff0c;本科生轻松搞定论文格式&#xff01; AI 工具如何让论文写作变得轻松高效 在当前的学术环境中&#xff0c;越来越多的学生开始借助 AI 工具来提升论文写作的效率。无论是从内容生成、格式调整&#xff0c;还是降重处理&#xff0c;这些…

不卖的天价胸罩:维多利亚的秘密的 “营销核武器”

为什么维多利亚的秘密要提供价值数百万美元的镶钻胸罩&#xff0c;即便从来没人买过&#xff1f;不卖的天价胸罩&#xff1a;维多利亚的秘密的 “营销核武器”维多利亚的秘密每年推出价值数百万美元的镶钻胸罩&#xff08;Fantasy Bra&#xff09;&#xff0c;却从未真正售出&a…

2026 年地铁广告公司综合实力排行榜单及全面选择指南:2026年地铁广告公司如何选?哪家好?哪家强?哪家靠谱?选哪家 - Top品牌推荐

地铁广告作为户外广告的重要组成部分,凭借其覆盖人群广、曝光率高、目标受众精准等优势,成为众多品牌推广的重要选择。本文将为您全面介绍国内主要的地铁广告公司、广告形式、价格策略及投放建议。 一、国内主要地铁…

AppScan_Std_9.0.3.5_Eval_Win使用步骤详解(附扫描与报告教程)

AppScan 9.0.3.5 是 IBM 出的一款Web应用安全扫描工具&#xff0c;专门用来找网站/系统的安全漏洞&#xff08;比如SQL注入、XSS跨站脚本、弱密码等&#xff09;。Eval是评估版&#xff0c;功能全但可能有时间限制&#xff0c;适合学习、测试或内部项目用。 它操作不算难&…

web入门41-50

web41 分析代码发现过滤了数字字母和一些符号,发现或(|)符号没有禁用,使用或运算表示各种符号,写一个脚本点击查看代码 import re import urllib from urllib import parse import requestscontents = [] for i in ra…

2026必备!9个AI论文写作软件,MBA毕业论文轻松搞定!

2026必备&#xff01;9个AI论文写作软件&#xff0c;MBA毕业论文轻松搞定&#xff01; AI 工具让论文写作更高效 随着人工智能技术的不断进步&#xff0c;越来越多的 AI 工具被应用于学术写作领域。对于 MBA 学生来说&#xff0c;撰写高质量的毕业论文不仅是学业的重要环节&…

2025年市场排行前列的清障车专业厂家哪个好,落地清障车/拖吊联体清障车/蓝牌重载清障车,清障车品牌排行榜 - 品牌推荐师

随着我国公路网络日益完善与汽车保有量持续攀升,道路救援与车辆清障需求呈现出专业化、高效化、场景化的发展趋势。清障车作为保障道路畅通、处理交通事故的关键装备,其市场需求正从单一功能向多场景、高可靠性、智能…

基于滑模变结构观测器的失磁故障容错补偿策略在永磁同步电机控制中的应用

基于失磁故障容错补偿的永磁同步电机控制【提供参考资料】 一、算法简介 基于滑模变结构观测器&#xff0c;将状态电流观测值作为反馈量&#xff0c;利用滑模变结构等值控制原理&#xff0c;建立实时估计永磁磁链算式&#xff0c;从而进行补偿。 避免因失磁导致的转速下降&…

巧用FX3U实现多种变频器控制:从原理到实操

fx3u和西门子v20/台达vfd-m/三菱E700 rtu所需硬件&#xff1a;FX3U PLC,FX3U-485BD通信板&#xff0c;变频器。 功能&#xff1a;使用fx3u-485bd板,rtu通信控制西门子v20/台达VFD-M/三菱E700三种变频器正反转&#xff0c;停止&#xff0c;频率设定&#xff0c;加减速&#xff0…

大模型回答:Typora是哪个国家的软件?

根据搜索结果&#xff0c;我可以回答你的问题&#xff1a; Typora的开发者国籍&#xff1a; Typora是由Abner Lee开发的&#xff0c;确切来说是国人&#xff08;中国开发者&#xff09;开发的软件。 多个来源都确认了这一点&#xff0c;有用户甚至表示"看这软件质量曾一度…

【2026最新 架构环境安装篇二】Docker安装MySQL8详细教程

#拉取MySQL镜像 docker pull mysql:8.0#创建本地目录&#xff08;用于挂载数据、配置&#xff09; mkdir -p ~/docker/mysql/data ~/docker/mysql/conf#启动容器&#xff08;挂载目录配置&#xff09; docker run -d \ --name mysql8 \ -p 3306:3306 \ -v ~/docker/mysql/data:…

2026年知名的AI搜索优化专业公司推荐,南方网通不容错过 - 工业品牌热点

在AI技术重塑商业生态的当下,AI搜索优化已成为企业抢占流量高地、实现精准获客的核心抓手。面对市场上良莠不齐的AI服务提供商,如何挑选真正能解决获客难、转化低、效率慢痛点的合作伙伴?以下结合不同服务定位,为你…

2026年金属衣架厂家权威推荐榜单:塑料衣架/铁制衣架/铝合金衣架/木衣架/不锈钢衣架源头厂家精选 - 品牌推荐官

在衣架领域,金属制品以其出色的承重性、耐用性和现代简约的美感,始终占据着稳固的市场份额。随着消费者对品质生活的追求与商业陈列要求的提升,市场对金属衣架在材料、工艺、功能设计乃至智能应用等方面都提出了更高…

双主轴定制排行,2025年优选品牌,刀塔车床/4+4车铣/双主轴双刀塔/动力刀塔/双主轴双排刀/数控4+4双主轴采购排行 - 品牌推荐师

随着制造业向高端化、智能化、柔性化方向深度转型,对复杂零部件“一次装夹,全部完工”的加工需求日益迫切。双主轴机床,作为车铣复合技术领域的核心装备,因其卓越的加工效率与精度,已成为精密机械、新能源汽车、医…

学校整站程序如何通过百度编辑器实现WORD图片批量上传?

Word一键转存CMS升级日记&#xff1a;从绝望到真香的全过程 Day 1&#xff1a;需求分析与技术调研 “淦&#xff01;论文格式又要改第8遍了&#xff01;”——这是我今天第18次想把Word文档扔出窗外时内心的呐喊。作为一名大三狗&#xff0c;我决定给我的CMS新闻系统加个&quo…

小米15堆叠桌面APK

小米15堆叠桌面APK分享 密码:2tmq

2025苏州恒温恒湿箱新排行,高端品质引领行业潮流!砂尘试验箱/淋雨试验箱/恒温恒湿房,恒温恒湿箱源头厂家有哪些 - 品牌推荐师

近年来,随着制造业对产品环境适应性要求的提升,恒温恒湿箱作为核心检测设备,市场需求持续攀升。据行业数据显示,2024年国内市场规模突破35亿元,其中长三角地区占比超40%,苏州凭借完善的产业链和科研资源,成为技…