当前位置: 首页 > ai >正文

注解 + AOP 的方式记录日志到 t_ops_sync_log 表

要实现通过注解 + AOP 的方式记录日志到 t_ops_sync_log 表,我们可以按照以下步骤进行:

1. 首先创建自定义注解

这个注解将用于标记需要记录日志的方法,并可以通过属性传递一些基本信息

2. 创建切面类

通过切面捕获被注解标记的方法,在环绕通知中记录方法执行的详细信息

import java.lang.annotation.*;/*** 数据同步日志注解*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OpsSyncLog {/*** 操作名*/String opsName() default "";/*** 是否记录方法参数*/boolean recordParams() default false;
}
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.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.UUID;/*** 数据同步日志切面*/
@Slf4j
@Aspect
@Component
public class OpsSyncLogAspect {@Resourceprivate IOpsSyncLogService opsSyncLogService;/*** 定义切点:拦截所有标注了OpsSyncLog注解的方法*/@Pointcut("@annotation(com.yourpackage.OpsSyncLog)")public void opsSyncLogPointCut() {}/*** 环绕通知:记录方法执行的详细信息*/@Around("opsSyncLogPointCut()")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {// 构建日志对象TOpsSyncLog syncLog = new TOpsSyncLog();syncLog.setId(UUID.randomUUID().toString().replaceAll("-", ""));syncLog.setCreateTime(new Date());syncLog.setUpdateTime(new Date());syncLog.setIsDelete(0);syncLog.setVersion(1);syncLog.setStatus(0); // 默认状态// 获取注解信息MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();OpsSyncLog opsSyncLog = method.getAnnotation(OpsSyncLog.class);// 设置操作名if (StringUtils.hasText(opsSyncLog.opsName())) {syncLog.setOpsName(opsSyncLog.opsName());} else {// 如果没有指定操作名,使用类名+方法名String className = joinPoint.getTarget().getClass().getSimpleName();syncLog.setOpsName(className + "." + method.getName());}syncLog.setOpsTime(new Date());// 记录开始时间long startTime = System.currentTimeMillis();Object result = null;try {// 执行目标方法result = joinPoint.proceed();// 方法执行成功syncLog.setResult("1"); // 1表示成功syncLog.setStatus(1);   // 成功状态return result;} catch (Throwable e) {// 方法执行异常syncLog.setResult("0"); // 0表示失败syncLog.setStatus(2);   // 失败状态// 记录异常信息,避免过长String errorMsg = e.getMessage();if (errorMsg != null && errorMsg.length() > 500) {errorMsg = errorMsg.substring(0, 500);}syncLog.setErrMsg(errorMsg);throw e; // 继续抛出异常,不影响原有业务逻辑} finally {// 计算运行时长long endTime = System.currentTimeMillis();syncLog.setRunningTime((int) (endTime - startTime));// 异步保存日志,不阻塞主流程saveLogAsync(syncLog);}}/*** 异步保存日志*/private void saveLogAsync(TOpsSyncLog syncLog) {try {// 这里可以使用线程池或@Async注解实现异步opsSyncLogService.save(syncLog);} catch (Exception e) {// 日志保存失败不影响主业务,只记录错误日志log.error("保存同步日志失败", e);}}
}
import java.util.Date;/*** 数据同步日志实体类*/
public class TOpsSyncLog {private String id;private String opsName;private Date opsTime;private Integer runningTime;private Integer runTimes;private Integer dataSize;private String result;private String errMsg;private String createBy;private Date createTime;private String updateBy;private Date updateTime;private Integer status;private Integer isDelete;private Integer version;// getter和setter方法public String getId() {return id;}public void setId(String id) {this.id = id;}public String getOpsName() {return opsName;}public void setOpsName(String opsName) {this.opsName = opsName;}public Date getOpsTime() {return opsTime;}public void setOpsTime(Date opsTime) {this.opsTime = opsTime;}public Integer getRunningTime() {return runningTime;}public void setRunningTime(Integer runningTime) {this.runningTime = runningTime;}public Integer getRunTimes() {return runTimes;}public void setRunTimes(Integer runTimes) {this.runTimes = runTimes;}public Integer getDataSize() {return dataSize;}public void setDataSize(Integer dataSize) {this.dataSize = dataSize;}public String getResult() {return result;}public void setResult(String result) {this.result = result;}public String getErrMsg() {return errMsg;}public void setErrMsg(String errMsg) {this.errMsg = errMsg;}public String getCreateBy() {return createBy;}public void setCreateBy(String createBy) {this.createBy = createBy;}public Date getCreateTime() {return createTime;}public void setCreateTime(Date createTime) {this.createTime = createTime;}public String getUpdateBy() {return updateBy;}public void setUpdateBy(String updateBy) {this.updateBy = updateBy;}public Date getUpdateTime() {return updateTime;}public void setUpdateTime(Date updateTime) {this.updateTime = updateTime;}public Integer getStatus() {return status;}public void setStatus(Integer status) {this.status = status;}public Integer getIsDelete() {return isDelete;}public void setIsDelete(Integer isDelete) {this.isDelete = isDelete;}public Integer getVersion() {return version;}public void setVersion(Integer version) {this.version = version;}
}
import org.springframework.stereotype.Service;/*** 使用示例*/
@Service
public class DataSyncService {/*** 被注解标记的方法会自动记录日志*/@OpsSyncLog(opsName = "用户数据同步")public void syncUserData() {// 业务逻辑实现try {// 模拟数据同步操作Thread.sleep(100);System.out.println("用户数据同步完成");} catch (InterruptedException e) {Thread.currentThread().interrupt();}}/*** 带参数的同步方法*/@OpsSyncLog(opsName = "订单数据同步")public void syncOrderData(int batchSize) {// 业务逻辑实现System.out.println("同步了" + batchSize + "条订单数据");}
}

实现说明

  1. 自定义注解 OpsSyncLog

    • 用于标记需要记录日志的方法
    • 可以指定操作名称,便于日志查询
  2. 切面类 OpsSyncLogAspect

    • 使用 @Around 环绕通知,可以捕获方法执行前后的信息
    • 记录方法执行时间、执行结果、异常信息等
    • 通过 finally 确保无论方法成功还是失败都会记录日志
    • 采用异步方式保存日志,避免影响主业务执行
    • 日志保存失败时仅记录错误日志,不影响主流程
  3. 关键特性

    • 完全不侵入业务代码,只需添加注解即可
    • 异常安全:即使日志记录失败,也不会影响原方法执行
    • 性能考虑:异步保存日志,避免阻塞主流程
    • 自动记录:操作时间、运行时长、执行结果、异常信息等关键信息
  4. 扩展建议

    • 可以根据需要扩展注解属性,如添加 dataSize 等字段的获取方式
    • 可以通过 SpEL 表达式从方法参数中提取更多信息
    • 对于 runTimes 等需要业务逻辑提供的字段,可以考虑通过 ThreadLocal 传递

使用时,只需在需要记录日志的方法上添加 @OpsSyncLog 注解即可,例如示例中的 syncUserData 和 syncOrderData 方法。

http://www.xdnf.cn/news/15890.html

相关文章:

  • 使用相机不同曝光时间测试灯光闪烁频率及Ai解释
  • 宝塔访问lnmp项目,跳转不到项目根目录问题解决
  • 后训练(Post-training)语言模型
  • Linux system-timesyncd时间同步机制详解
  • Django模板系统
  • Oracle 数据库共享池与大池调优指南
  • RuoYi配置多数据源失效
  • 【烧脑算法】拓扑排序:从“依赖”到“序列”,理解题目中的先后逻辑
  • 虚拟电厂蓄势:源网荷储联动如何实现电力系统的 “智慧蝶变”?
  • 如何升级到macOS Tahoe:全面指南与实用步骤
  • 从一开始的网络攻防(六):php反序列化
  • 关于JavaWeb的总结笔记
  • 云原生周刊:K8s 中的后量子密码学
  • 【学习路线】C#企业级开发之路:从基础语法到云原生应用
  • docker 容器学习
  • zabbix企业级分布式监控环境部署
  • 【Prometheus+Grafana篇】监控通过Keepalived实现的MySQL HA高可用架构
  • 在翻译语义相似度和会议摘要相似度评估任务中 ,分类任务 回归任务 生成任务区别
  • 布局AI +文化新赛道,浙江省文化产业投资集团赴景联文科技调研交流
  • uniapp【uni-ui】【vue3】样式覆盖方式记录
  • Git上传与下载GitHub仓库
  • Neo4j 5.x版本的导出与导入数据库
  • 【系统全面】Linux内核原理——基础知识介绍
  • Python-数据库概念-pymysql-元编程-SQLAlchemy-学习笔记
  • 【ASP.NET Core】ASP.NET Core中Redis分布式缓存的应用
  • Python day20 - 特征降维之奇异值分解
  • 隧道代理的动态IP切换机制与实现原理
  • 农村供水智慧化管理系统:从精准监测到智能调度,破解农村用水安全与效率难题
  • 康复器材动静态性能测试台:精准检测,为康复器械安全保驾护航
  • Gradio项目部署到魔搭创空间