SpringBoot通过自定义注解与异步来管理日志流程

目录
  • 一、前言
  • 二、基础环境
    • 1. 导入依赖
    • 2. 编写yml配置
  • 三、数据库设计
  • 四、主要功能
    • 1. 编写注解
    • 2. 业务类型枚举
    • 3. 编写切片
    • 4. ip工具类
    • 5. 事件发布
    • 6. 监听者
  • 五、测试
    • 1. controller
    • 2. service
    • 3. dao
    • 4. 测试
    • 5. 数据库
  • 六、总结

一、前言

我们在企业级的开发中,必不可少的是对日志的记录,实现有很多种方式,常见的就是基于AOP+注解进行保存,同时考虑到程序的流畅和效率,我们可以使用异步进行保存!

二、基础环境

1. 导入依赖

我这里的springboot版本是:2.7.4

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>springboot-log</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-log</name>
    <description>springboot-log 日志 Demo</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- Druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.16</version>
        </dependency>
        <!--jdbc-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!-- mybatis-plus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2. 编写yml配置

server:
  port: 8080

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/admin?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    druid:
      initial-size: 5
      max-active: 100
      min-idle: 5
      max-wait: 60000
      time-between-eviction-runs-millis: 60000
      min-evictable-idle-time-millis: 30000
      validation-query: SELECT 1 FROM DUAL
      test-while-idle: true
      test-on-borrow: true
      test-on-return: false

三、数据库设计

数据库保存日志表的设计,这里一切从简,一般日志多的后期会进行分库分表,或者搭配ELK进行分析,分库分表一般采用根据方法类型!

DROP TABLE IF EXISTS `sys_log`;
CREATE TABLE `sys_log`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '日志主键',
  `title` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '模块标题',
  `business_type` int(2) NULL DEFAULT 0 COMMENT '业务类型(0其它 1新增 2修改 3删除)',
  `method` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '方法名称',
  `request_method` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '请求方式',
  `oper_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '操作人员',
  `oper_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '请求URL',
  `oper_ip` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '主机地址',
  `oper_time` datetime(0) NULL DEFAULT NULL COMMENT '操作时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1585197503834284034 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '操作日志记录' ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;

实体类:

package com.example.springbootlog.entity;
import java.util.Date;
import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.ToString;
/**
 * 操作日志记录(SysLog)实体类
 *
 * @author qrxm
 * @since 2023-03-26 02:09:54
 */
@Data
@ToString
@TableName("sys_log")
public class SysLog implements Serializable {
    private static final long serialVersionUID = 811241510868515068L;
    /**
    * 日志主键
    */
    @TableId
    private Long id;
    /**
    * 模块标题
    */
    private String title;
    /**
    * 业务类型(0其它 1新增 2修改 3删除)
    */
    private Integer businessType;
    /**
    * 方法名称
    */
    private String method;
    /**
    * 请求方式
    */
    private String requestMethod;
    /**
    * 操作人员
    */
    private String operName;
    /**
    * 请求URL
    */
    private String operUrl;
    /**
    * 主机地址
    */
    private String operIp;
    /**
    * 操作时间
    */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date operTime;
}

四、主要功能

大体思路:

  • 先手写一个注解
  • 切面来进行获取要保存的数据
  • 一个发布者来发布要保存的数据
  • 一个监听者监听后保存(异步)

完整项目架构图如下:

1. 编写注解

package com.example.springbootlog.annotation;
import com.example.springbootlog.constant.BusinessTypeEnum;
import java.lang.annotation.*;
/**
 * 自定义操作日志记录注解
 * @author qrxm
 */
@Target(ElementType.METHOD) // 注解只能用于方法
@Retention(RetentionPolicy.RUNTIME) // 修饰注解的生命周期
@Documented
public @interface Log {
    String value() default "";
    /**
     * 模块
     */
    String title() default "测试模块";
    /**
     * 方法名称
     */
    String method() default "测试方法";
    /**
     * 功能
     */
    BusinessTypeEnum businessType() default BusinessTypeEnum.OTHER;
}

2. 业务类型枚举

package com.example.springbootlog.constant;
public enum BusinessTypeEnum {
    /**
     * 其它
     */
    OTHER(0,"其它"),
    /**
     * 新增
     */
    INSERT(1,"新增"),
    /**
     * 修改
     */
    UPDATE(2,"修改"),
    /**
     * 删除
     */
    DELETE(3,"删除");
    private Integer code;
    private String message;
    BusinessTypeEnum(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
    public Integer getCode() {
        return code;
    }
    public String getMessage() {
        return message;
    }
}

3. 编写切片

这里是以切片后进行发起的,当然规范流程是要加异常后的切片,这里以最简单的进行测试哈,大家按需进行添加!!

package com.example.springbootlog.aspect;
import com.example.springbootlog.annotation.Log;
import com.example.springbootlog.entity.SysLog;
import com.example.springbootlog.listener.EventPubListener;
import com.example.springbootlog.utils.IpUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.Date;
@Aspect
@Component
public class SysLogAspect {
    private final Logger logger = LoggerFactory.getLogger(SysLogAspect.class);
    @Autowired
    private EventPubListener eventPubListener;
    /**
     * 以注解所标注的方法作为切入点
     */
    @Pointcut("@annotation(com.example.springbootlog.annotation.Log)")
    public void sysLog() {}
    /**
     * 在切点之后织入
     * @throws Throwable
     */
    @After("sysLog()")
    public void doAfter(JoinPoint joinPoint) {
        Log log = ((MethodSignature) joinPoint.getSignature()).getMethod()
                .getAnnotation(Log.class);
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String method = request.getMethod();
        String url = request.getRequestURL().toString();
        String ip = IpUtils.getIpAddr(request);
        SysLog sysLog = new SysLog();
        sysLog.setBusinessType(log.businessType().getCode());
        sysLog.setTitle(log.title());
        sysLog.setMethod(log.method());
        sysLog.setRequestMethod(method);
        sysLog.setOperIp(ip);
        sysLog.setOperUrl(url);
        // 从登录中token获取登录人员信息即可
        sysLog.setOperName("我是测试人员");
        sysLog.setOperTime(new Date());
        // 发布消息
        eventPubListener.pushListener(sysLog);
        logger.info("=======日志发送成功,内容:{}",sysLog);
    }
}

4. ip工具类

package com.example.springbootlog.utils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import javax.servlet.http.HttpServletRequest;
public class IpUtils {
    /**
     * 获取客户端IP
     *
     * @param request 请求对象
     * @return IP地址
     */
    public static String getIpAddr(HttpServletRequest request) {
        if (request == null) {
            return "unknown";
        }
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Forwarded-For");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip);
    }
    /**
     * 从多级反向代理中获得第一个非unknown IP地址
     *
     * @param ip 获得的IP地址
     * @return 第一个非unknown IP地址
     */
    public static String getMultistageReverseProxyIp(String ip) {
        // 多级反向代理检测
        if (ip != null && ip.indexOf(",") > 0) {
            final String[] ips = ip.trim().split(",");
            for (String subIp : ips) {
                if (false == isUnknown(subIp)) {
                    ip = subIp;
                    break;
                }
            }
        }
        return ip;
    }
    /**
     * 检测给定字符串是否为未知,多用于检测HTTP请求相关
     *
     * @param checkString 被检测的字符串
     * @return 是否未知
     */
    public static boolean isUnknown(String checkString) {
        return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString);
    }
}

5. 事件发布

事件发布是由ApplicationContext对象进行发布的,直接注入使用即可!

使用观察者模式的目的:为了业务逻辑之间的解耦,提高可扩展性。

这种模式在spring和springboot底层是经常出现的,大家可以去看看。

发布者只需要关注发布消息,监听者只需要监听自己需要的,不管谁发的,符合自己监听条件即可。

package com.example.springbootlog.listener;
import com.example.springbootlog.entity.SysLog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
@Component
public class EventPubListener {
    @Autowired
    private ApplicationContext applicationContext;
    /**
     * 事件发布方法
     * @param sysLogEvent
     */
    public void pushListener(SysLog sysLogEvent) {
        applicationContext.publishEvent(sysLogEvent);
    }
}

6. 监听者

@Async:单独开启一个新线程去保存,提高效率!

@EventListener:监听

package com.example.springbootlog.listener;
import com.example.springbootlog.entity.SysLog;
import com.example.springbootlog.service.SysLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class MyEventListener {
    @Autowired
    private SysLogService sysLogService;
    // 开启异步
    @Async
    // 开启监听
    @EventListener(SysLog.class)
    public void saveSysLog(SysLog event) {
        log.info("=====即将异步保存到数据库======");
        sysLogService.saveLog(event);
    }
}

五、测试

1. controller

package com.example.springbootlog.controller;
import com.example.springbootlog.annotation.Log;
import com.example.springbootlog.constant.BusinessTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
/**
 * 操作日志记录(SysLog)表控制层
 *
 */
@Slf4j
@RestController
@RequestMapping("sysLog")
public class SysLogController {
    @Log(method = "测试添加方法", title = "测试呢", businessType = BusinessTypeEnum.INSERT)
    @GetMapping("/saveLog")
    public void saveLog() {
        log.info("我就是来测试一下是否成功!");
    }
}

2. service

package com.example.springbootlog.service;
import com.example.springbootlog.entity.SysLog;
import com.baomidou.mybatisplus.extension.service.IService;
/**
 * 操作日志记录(SysLog)表服务接口
 */
public interface SysLogService  extends IService<SysLog> {
    Integer saveLog(SysLog sysLog);
}
package com.example.springbootlog.service.impl;
import com.example.springbootlog.entity.SysLog;
import com.example.springbootlog.service.SysLogService;
import com.example.springbootlog.dao.SysLogDao;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
 * 操作日志记录(SysLog)表服务实现类
 */
@Service("sysLogService")
public class SysLogServiceImpl  extends ServiceImpl<SysLogDao, SysLog>  implements SysLogService {
    @Autowired
    private SysLogDao sysLogDao;
    @Override
    public Integer saveLog(SysLog sysLog) {
        return sysLogDao.insert(sysLog);
    }
}

3. dao

这里使用mybatis-plus进行保存

package com.example.springbootlog.dao;
import com.example.springbootlog.entity.SysLog;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
 * 操作日志记录(SysLog)表数据库访问层
 */
public interface SysLogDao extends BaseMapper<SysLog> {
}

4. 测试

访问地址:http://localhost:8080/sysLog/saveLog

5. 数据库

六、总结

这个实战在企业级必不可少的,每个项目搭建人不同,但是结果都是一样的,保存日志到数据,这样可以进行按钮的点击进行统计,分析那个功能是否经常使用,那些东西需要优化。只要是有数据的东西,分析一下总会有收获的!后面日志多了就行分库分表,ELK搭建。

代码已上传到 Gitee 上面了,地址:https://gitee.com/afoams/springboot-log

到此这篇关于SpringBoot通过自定义注解与异步来管理日志流程的文章就介绍到这了,更多相关SpringBoot自定义注解内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • SpringBoot通过自定义注解实现参数校验

    目录 1. 为什么要进行参数校验 2. 如何实现参数校验 3. 注解实现参数校验 4. 自定义注解实现参数校验 1. 为什么要进行参数校验 在后端进行工作时,需要接收前端传来的数据去数据库查询,但是如果有些数据过于离谱,我们就可以直接把它pass掉,不让这种垃圾数据接触数据库,减小数据库的压力. 有时候会有不安分的人通过一些垃圾数据攻击咱们的程序,让咱们的服务器或数据库崩溃,这种攻击虽然低级但不得不防,就像QQ进行登录请求时,它们向后端发送 账号=123,密码=123 的数据,一秒钟还发1w次,

  • SpringBoot搭配AOP实现自定义注解

    目录 1.springBoot的依赖 2.自定义注解的步骤 2.1定义注解类 2.2定义切面 2.3使用注解 3.知识点补充 3.1 关于Target注解补充 3.2 关于Retention注解补充 3.3 关于AOP的一些概念补充 3.4关于AOP中一些类及函数的使用 1.springBoot的依赖 确定项目中包含可以注解的依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactI

  • SpringBoot 自定义注解异步记录复杂日志详解

    目录 1.背景 2.技术方案-自定义注解 2.1 注解介绍 2.2 元注解 2.3 实现自定义注解 3.技术方案-AOP切面 3.1 AOP术语解析 3.2 切入点表达式 3.3 ADVICE通知类型 3.4 技术实现 3.5 相关操作 4.高级操作 1.背景 最近接手一个任务,需要给当前项目加一个较为复杂的日志.有多复杂呢? 要有日志类型.不同日志类型要有不同的操作和备注等.作为小白的我最开始的做法是在业务层写代码记录日志,好处就是方便,坏处就是这种做法直接侵袭Service层,Service

  • SpringBoot 自定义注解实现涉密字段脱敏

    目录 1. 创建隐私数据类型枚举:PrivacyTypeEnum 2. 创建自定义隐私注解:PrivacyEncrypt 3. 创建自定义序列化器:PrivacySerializer 4. 隐私数据隐藏工具类:PrivacyUtil 5. 注解使用 关于数据脱敏,网上的文章都是硬编码规则,比如对身份证,手机号,邮件地址等固定写法脱敏.本文在此基础上,拓展动态从数据库查出涉密关键字执行脱敏操作. 数据脱敏:把系统里的一些敏感数据进行加密处理后再返回,达到保护隐私作用,实现效果图如下: 其实要实现上

  • springboot使用自定义注解实现aop切面日志

    平时我们在开发过程中,代码出现bug时为了更好的在服务器日志中寻找问题根源,会在接口的首尾打印日志,看下参数和返回值是否有问题.但是手动的logger.info() 去编写时工作量较大,这时我们可以使用AOP切面,为所有接口的首尾打印日志. 实现AOP切面日志一般有两种方式: 1.拦截所有接口controller,在首尾打印日志2.拦截指定注解的接口,为有该注解的接口首尾打印日志 我们尝试用自定义注解来实现AOP日志的打印,这样拥有更高的灵活性.废话不多说,我们开始 1. 导入切面需要的依赖包

  • SpringBoot通过自定义注解与异步来管理日志流程

    目录 一.前言 二.基础环境 1. 导入依赖 2. 编写yml配置 三.数据库设计 四.主要功能 1. 编写注解 2. 业务类型枚举 3. 编写切片 4. ip工具类 5. 事件发布 6. 监听者 五.测试 1. controller 2. service 3. dao 4. 测试 5. 数据库 六.总结 一.前言 我们在企业级的开发中,必不可少的是对日志的记录,实现有很多种方式,常见的就是基于AOP+注解进行保存,同时考虑到程序的流畅和效率,我们可以使用异步进行保存! 二.基础环境 1. 导入

  • SpringBoot通过自定义注解实现配置类的自动注入的实现

    目录 前言 实现思路 自定义配置类读取配置 自定义注解 创建子配置Bean 通过反射进行people bean的注入 使用 效果 回顾 延伸 前言 SpringBoot中通过@ConfigurationProperties或@Value注解就可以获取配置文件中的属性定义并绑定到Java Bean或属性上,这也是我们平常使用最多的一种方式.但是小胖在开发过程中就遇到一个问题:在做MQ的开发中,配置文件中会配置多个生产者分别提供不同的业务能力,如果通过@ConfigurationProperties

  • SpringBoot使用自定义注解实现权限拦截的示例

    本文介绍了SpringBoot使用自定义注解实现权限拦截的示例,分享给大家,具体如下: HandlerInterceptor(处理器拦截器) 常见使用场景 日志记录: 记录请求信息的日志, 以便进行信息监控, 信息统计, 计算PV(page View)等 性能监控: 权限检查: 通用行为: 使用自定义注解实现权限拦截 首先HandlerInterceptor了解 在HandlerInterceptor中有三个方法: public interface HandlerInterceptor { //

  • SpringBoot通过自定义注解实现日志打印的示例代码

    前言 在我们日常的开发过程中通过打印详细的日志信息能够帮助我们很好地去发现开发过程中可能出现的Bug,特别是在开发Controller层的接口时,我们一般会打印出Request请求参数和Response响应结果,但是如果这些打印日志的代码相对而言还是比较重复的,那么我们可以通过什么样的方式来简化日志打印的代码呢? SpringBoot 通过自定义注解实现权限检查可参考我的博客:SpringBoot 通过自定义注解实现权限检查 正文 Spring AOP Spring AOP 即面向切面,是对OO

  • SpringBoot中自定义注解实现参数非空校验的示例

    前言 由于刚写项目不久,在写 web 后台接口时,经常会对前端传入的参数进行一些规则校验,如果入参较少还好,一旦需要校验的参数比较多,那么使用 if 校验会带来大量的重复性工作,并且代码看起来会非常冗余,所以我首先想到能否通过一些手段改进这点,让 Controller 层减少参数校验的冗余代码,提升代码的可阅读性. 经过阅读他人的代码,发现使用 annotation 注解是一个比较方便的手段,SpringBoot 自带的 @RequestParam 注解只会校验请求中该参数是否存在,但是该参数是

  • SpringBoot用@Async注解实现异步任务

    什么是异步调用? 异步调用是相对于同步调用而言的,同步调用是指程序按预定顺序一步步执行,每一步必须等到上一步执行完后才能执行,异步调用则无需等待上一步程序执行完即可执行. 如何实现异步调用? 多线程,这是很多人第一眼想到的关键词,没错,多线程就是一种实现异步调用的方式. 在非spring目项目中我们要实现异步调用的就是使用多线程方式,可以自己实现Runable接口或者集成Thread类,或者使用jdk1.5以上提供了的Executors线程池. StrngBoot中则提供了很方便的方式执行异步调

  • 详解springboot通过Async注解实现异步任务及回调的方法

    目录 前言 什么是异步调用? 1. 环境准备 2. 同步调用 3. 异步调用 4. 异步回调 前言 什么是异步调用? 异步调用是相对于同步调用而言的,同步调用是指程序按预定顺序一步步执行,每一步必须等到上一步执行完后才能执行,异步调用则无需等待上一步程序执行完即可执行.异步调用可以减少程序执行时间. 1. 环境准备 在 Spring Boot 入口类上配置 @EnableAsync 注解开启异步处理.创建任务抽象类 AbstractTask,并实现三个任务方法 doTaskOne(),doTas

  • SpringBoot使用自定义注解+AOP+Redis实现接口限流的实例代码

    目录 为什么要限流 限流背景 实现限流 1.引入依赖 2.自定义限流注解 3.限流切面 4.写一个简单的接口进行测试 5.全局异常拦截 6.接口测试 为什么要限流 系统在设计的时候,我们会有一个系统的预估容量,长时间超过系统能承受的TPS/QPS阈值,系统有可能会被压垮,最终导致整个服务不可用.为了避免这种情况,我们就需要对接口请求进行限流. 所以,我们可以通过对并发访问请求进行限速或者一个时间窗口内的的请求数量进行限速来保护系统或避免不必要的资源浪费,一旦达到限制速率则可以拒绝服务.排队或等待

  • SpringBoot使用自定义注解实现数据脱敏过程详细解析

    目录 前言 一.引入hutool工具类 二.定义常用需要脱敏的数据类型的枚举 三.定义脱敏方式枚举 四.自定义脱敏的注解 五.自定义Jackson的序列化方式 六.使用 七.脱敏效果 前言 对于某些接口返回的信息,涉及到敏感数据的必须进行脱敏操作,例如银行卡号.身份证号.手机号等,脱敏方式有多种方式.可以修改SQL语句,也可以写硬代码,也可以修改JSON序列化,这里介绍通过修改Jackson序列化方式实现数据脱敏. 一.引入hutool工具类 maven: <dependency> <g

随机推荐