SpringBoot+自定义注解+AOP高级玩法打造通用开关

这篇具有很好参考价值的文章主要介绍了SpringBoot+自定义注解+AOP高级玩法打造通用开关。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.项目结构
SpringBoot+自定义注解+AOP高级玩法打造通用开关,Spring Boot,spring boot,java,AOP,注解
2.引入依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
    </dependencies>

3.yml配置

server:
  port: 8080
spring:
  redis:
    database: 0
    host: x.x.x.x
    port: 6379
    password: 123456
    jedis:
      pool:
        max-active: 10
        max-wait: -1ms
        max-idle: 5
        min-idle: 1

4.自定义注解

package com.example.springbootaop.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * 通用开关注解
 * @author shixc
 * 2023/10/17
 */
@Target({ElementType.METHOD})  // 作用在方法上
@Retention(RetentionPolicy.RUNTIME)  // 运行时起作用
public @interface ServiceSwitch {
    /**
     * 业务开关的key(不同key代表不同功效的开关)
     * {@link Constant.ConfigCode}
     */
    String switchKey();
    // 开关,0:关(拒绝服务并给出提示),1:开(放行)
    String switchVal() default "0";
    // 提示信息,默认值可在使用注解时自行定义。
    String message() default "当前请求人数过多,请稍后重试。";
}

5.定义常量

package com.example.springbootaop.constant;
/**
 * 常量
 * @author shixc
 * 2023/10/17
 */
public class Constant {
    // .... 其他业务相关的常量 ....
    // 配置相关的常量
    public static class ConfigCode {
        // 挂号支付开关(0:关,1:开)
        public static final String REG_PAY_SWITCH = "reg_pay_switch";
        // 其他业务相关的配置常量
        // ....
    }
}

6.AOP核心实现

package com.example.springbootaop.aop;
import com.example.springbootaop.annotation.ServiceSwitch;
import com.example.springbootaop.constant.Constant;
import com.example.springbootaop.util.Result;
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.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
 * AOP核心实现
 * @author shixc
 * 2023/10/17
 */
@Aspect
@Component
public class ServiceSwitchAOP {
    private final StringRedisTemplate redisTemplate;
    public ServiceSwitchAOP(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }
    /**
     * 定义切点,使用了@ServiceSwitch注解的类或方法都拦截
     */
    @Pointcut("@annotation(com.example.springbootaop.annotation.ServiceSwitch)")
    public void pointcut() {
    }
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint point) {
        // 获取被代理的方法的参数
        Object[] args = point.getArgs();
        // 获取被代理的对象
        Object target = point.getTarget();
        // 获取通知签名
        MethodSignature signature = (MethodSignature) point.getSignature();

        try {

            // 获取被代理的方法
            Method method = target.getClass().getMethod(signature.getName(), signature.getParameterTypes());
            // 获取方法上的注解
            ServiceSwitch annotation = method.getAnnotation(ServiceSwitch.class);
            // 核心业务逻辑
            if (annotation != null) {
                String switchKey = annotation.switchKey();
                String switchVal = annotation.switchVal();
                String message = annotation.message();
            /*
              获取配置项说明
              这里有两种方式:1、配置加在Redis,查询时从Redis获取;
                          2、配置加在数据库,查询时从表获取。(MySQL单表查询其实很快,配置表其实也没多少数据)
              我在工作中的做法:直接放到数据库,但是获取配置项的方法用SpringCache缓存,
                           然后在后台管理中操作配置项,变更时清理缓存即可。
                           我这么做就是结合了上面两种各自的优点,因为项目中配置一般都是用后台管理来操作的,
                           查表当然更舒适,同时加上缓存提高查询性能。
             */

                // 下面这块查询配置项,大家可以自行接入并修改。
                // 数据库这么查询:String configVal = systemConfigService.getConfigByKey(switchKey);
                // 这里我直接从redis中取,使用中大家可以按照意愿自行修改。
                String configVal = redisTemplate.opsForValue().get(Constant.ConfigCode.REG_PAY_SWITCH);
                if (switchVal.equals(configVal)) {
                    // 开关打开,则返回提示。
                    return Result.fail(HttpStatus.FORBIDDEN.value()+"", message);
                }
            }
            // 放行
            return point.proceed(args);
        } catch (Throwable e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }
}

7.使用注解

package com.example.springbootaop.service;
import com.example.springbootaop.annotation.ServiceSwitch;
import com.example.springbootaop.constant.Constant;
import com.example.springbootaop.util.Result;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
/**
 * @author shixc
 * 2023/10/17
 */
@Service
public class RegService {
    /**
     * 挂号下单
     */
    @ServiceSwitch(switchKey = Constant.ConfigCode.REG_PAY_SWITCH)
    public Result createOrder() {
        // 具体下单业务逻辑省略....
        return Result.succeed("挂号下单成功");
    }
}

8.工具类

import java.io.Serializable;
/**
 * @author shixc
 * 2023/10/17
 */
public final class Result<T> implements Serializable {
    private static final long serialVersionUID = -8780880627029425781L;
    private String code;
    private long timestamp = System.currentTimeMillis();
    private String message;
    private T data;
    public Result() {
    }
    private Result(String code, String message, T data) {
        this.code = code;
        this.message = message;
        this.data = data;
    }
    public String getCode() {
        return this.code;
    }
    public long getTimestamp() {
        return this.timestamp;
    }
    public String getMessage() {
        return this.message;
    }
    public T getData() {
        return this.data;
    }
    public static <T> Result<T> succeed() {
        return new Result("0", "", (Object) null);
    }
    public static <T> Result<T> succeed(T data) {
        return new Result("0", "", data);
    }
    public static <T> Result<T> panic() {
        return new Result("000000", "系统运行发生异常,请联系IT处理", (Object) null);
    }
    public static <T> Result<T> illegalArgument(String message) {
        return new Result("000001", message, (Object) null);
    }
    public static <T> Result<T> fail(String code, String message) {
        return new Result(code, message, (Object) null);
    }
    public static <T> Result<T> fail(String code, String message, T data) {
        return new Result(code, message, data);
    }
    public boolean success() {
        return this.code.equals("0");
    }
    public boolean failure() {
        return !this.success();
    }
}

9.测试接口

package com.example.springbootaop.controller;
import com.example.springbootaop.service.RegService;
import com.example.springbootaop.util.Result;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
 * 挂号Controller
 * @author shixc
 * 2023/10/17
 */
@RestController
@RequestMapping("reg")
public class RegController {
    private final RegService regService;
    public RegController(RegService regService) {
        this.regService = regService;
    }
    @GetMapping("/create")
    public Result createOrder() {
        return regService.createOrder();
    }
}

10.Redis中把开关加上
SpringBoot+自定义注解+AOP高级玩法打造通用开关,Spring Boot,spring boot,java,AOP,注解
11.启动服务
SpringBoot+自定义注解+AOP高级玩法打造通用开关,Spring Boot,spring boot,java,AOP,注解
将redis中开关置为1
SpringBoot+自定义注解+AOP高级玩法打造通用开关,Spring Boot,spring boot,java,AOP,注解
欢迎大家积极留言交流学习心得,点赞的人最美丽!文章来源地址https://www.toymoban.com/news/detail-722754.html

到了这里,关于SpringBoot+自定义注解+AOP高级玩法打造通用开关的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • springboot3使用自定义注解+AOP+redis优雅实现防重复提交

      ⛰️个人主页:     蒾酒 🔥 系列专栏 :《spring boot实战》 🌊 山高路远,行路漫漫,终有归途 目录 写在前面 实现思路 实现步骤 1.定义防重复提交注解 2.编写一个切面去发现该注解然后执行防重复提交逻辑 3.测试 依赖条件 1.接口上标记防重复提交注解 2.接口测试 写在最

    2024年04月11日
    浏览(36)
  • Springboot 中使用 Redisson+AOP+自定义注解 实现访问限流与黑名单拦截

    🏷️ 个人主页 :牵着猫散步的鼠鼠  🏷️ 系列专栏 :Java全栈-专栏 🏷️ 个人学习笔记,若有缺误,欢迎评论区指正   前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站AI学习网站。 目录 前言 1.导入Redisson 引入依

    2024年02月21日
    浏览(52)
  • SpringBoot自定义注解+AOP+redis实现防接口幂等性重复提交,从概念到实战

    本文为千锋教育技术团独家创作,更多技术类知识干货,点个关注持续追更~ 接口幂等性是Web开发中非常重要的一个概念,它可以保证多次调用同一个接口不会对结果产生影响。如果你想了解更多关于接口幂等性的知识,那么本文就是一个不错的起点。 在Web开发中,我们经常

    2024年02月03日
    浏览(53)
  • 根据aop实现自定义缓存注解

    自定义注解 切面 使用

    2024年02月13日
    浏览(53)
  • spring自定义注解+aop+@BindingParam

    2.1 声明切面注解  2.1.1切面对应枚举  2.2 声明绑定参数注解 4.1 ThreadLocalUtil  4.2  自定义异常

    2024年02月14日
    浏览(38)
  • 【SpringMVC】自定义注解与AOP结合使用

    目录 一、SpringMVC之自定义注解 1.1 Java注解简介 1.2 为什么要用注解 1.3 注解的分类 ⭐ 1.3.1 JDK基本注解 1.3.2 JDK元注解  1.3.3 自定义注解  1.4 自定义注解三种使用案例 1.4.1 案例一(获取类与方法上的注解值) 1.4.2 案例二(获取类属性上的注解属性值) 1.4.3 案例三(获取参数

    2024年02月07日
    浏览(65)
  • 【Spring】使用自定义注解方式实现AOP鉴权

    AOP,是一种面向切面编程,可以通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。 在软件开发中,鉴权(Authentication)是一项非常重要的安全措施,用于验证用户身份和权限。在应用程序中,我们通常会使用AOP(Aspect-Oriented Programming)来实现鉴权功能

    2024年02月11日
    浏览(46)
  • redis + AOP + 自定义注解实现接口限流

    限流(rate limiting) ​ 是指在一定时间内,对某些资源的访问次数进行限制,以避免资源被滥用或过度消耗。限流可以防止服务器崩溃、保证用户体验、提高系统可用性。 限流的方法有很多种,常见的有以下几种: 漏桶算法: ​漏桶算法通过一个固定大小的漏桶来模拟流量

    2024年02月03日
    浏览(32)
  • 【SpringBoot应用篇】【AOP+注解】SpringBoot+SpEL表达式基于注解实现权限控制

    Spring 表达式语言 SpEL 是一种非常强大的表达式语言,它支持在运行时查询和操作对象图。 它提供了许多高级功能,例如方法调用和基本的字符串模板功能。 表达式语言给静态Java语言增加了动态功能。 Spring 表达式语言最初是为 Spring 社区创建的,它拥有一种受良好支持的表

    2024年02月20日
    浏览(43)
  • Spring Boot 自定义注解,AOP 切面统一打印出入参请求日志

    今天主要说说如何通过自定义注解的方式,在 Spring Boot 中来实现 AOP 切面统一打印出入参日志。小伙伴们可以收藏一波。 废话不多说,进入正题! 在看看实现方法之前,我们先看下切面日志输出效果咋样: 从上图中可以看到,每个对于每个请求,开始与结束一目了然,并且

    2024年02月08日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包