当前位置:首页 > 科技  > 软件

优雅实现API接口开关:让你的应用更可控

来源: 责编: 时间:2023-11-28 09:32:33 305观看
导读环境:SpringBoot2.7.121. 概述本文将介绍如何为API接口动态添加开关功能。通过这个功能,我们可以控制API接口的正常访问或显示提示信息。这有助于在开发和维护过程中更好地管理和控制API接口的行为。通过使用开关功能,我

环境:SpringBoot2.7.12OLU28资讯网——每日最新资讯28at.com

1. 概述

本文将介绍如何为API接口动态添加开关功能。通过这个功能,我们可以控制API接口的正常访问或显示提示信息。这有助于在开发和维护过程中更好地管理和控制API接口的行为。通过使用开关功能,我们可以轻松地在不同情况下调整接口的行为,提高系统的灵活性和可维护性。OLU28资讯网——每日最新资讯28at.com

为什么要给API接口添加开关功能呢?从以下几方面考虑:OLU28资讯网——每日最新资讯28at.com

  1. 灵活性和可扩展性:我们可以根据需要动态地控制API接口的行为。这使得在面对不同场景和需求时,可以更加灵活地调整接口的行为,而无需对代码进行修改。
  2. 安全性和控制:有时,我们可能不希望在特定情况下API接口被正常访问,例如在测试、维护或敏感数据访问等场景下。通过关闭开关并显示提示信息,我们可以对用户进行必要的通知和引导,确保接口不被未经授权的访问。
  3. 错误处理和日志记录:当API接口出现错误或异常时,关闭开关并显示提示信息可以帮助我们更好地追踪和记录问题。这对于后续的问题排查和系统优化非常有帮助。
  4. 系统监控和管理:通过监控开关状态的变化,我们可以了解系统的运行状况,以及用户对API接口的使用情况。这有助于进行系统性能优化和资源管理。
  5. 用户体验:在某些情况下,当API接口不可用或需要维护时,向用户显示友好的提示信息可以避免用户感到困惑或带来不必要的困扰。同时,提前通知用户也体现了对用户体验的关注。
  6. 合规性和隐私保护:在涉及敏感数据或受限制的API接口中,通过关闭开关并显示提示信息,可以确保遵守相关法规和隐私政策,对数据进行适当的管理和保护。

2. 实现方案

首先,定义一个AOP切面(Aspect),该切面负责控制接口(Controller)的开关行为。OLU28资讯网——每日最新资讯28at.com

在切面中,我们可以使用Spring AOP的切入点(Pointcut)来指定需要拦截的方法。一旦方法被拦截,我们可以在切面的通知(Advice)中定义相应的默认行为。接下来我们将一步一步的实现接口开关功能。OLU28资讯网——每日最新资讯28at.com

  • 自定义注解
@Target({ElementType.TYPE, ElementType.METHOD})public @interface ApiSwitch {  /**接口对应的key,通过可以该key查询接口是否关闭*/  String key() default "" ;    /**解析器beanName,通过具体的实现获取key对应的值*/  String resolver() default "" ;    /**开启后降级方法名*/  String fallback() default "" ;  }
  • 定义解析器接口
public interface SwitchResolver {  boolean resolver(String key) ;    public void config(String key, Integer onoff) ;  }
  • 接口默认实现
@Componentpublic class ConcurrentMapResolver implements SwitchResolver {  private Map<String, Integer> keys = new ConcurrentHashMap<>() ;    @Override  public boolean resolver(String key) {    Integer value = keys.get(key) ;    return value == null ? false : (value == 1) ;  }    public void config(String key, Integer onoff) {    keys.put(key, onoff) ;  }}
  • 基于redis实现
@Componentpublic class RedisResolver implements SwitchResolver {  private final StringRedisTemplate stringRedisTemplate ;    public RedisResolver(StringRedisTemplate stringRedisTemplate) {    this.stringRedisTemplate = stringRedisTemplate ;  }    @Override  public boolean resolver(String key) {    String value = this.stringRedisTemplate.opsForValue().get(key) ;    return !(value == null || "0".equals(value)) ;  }  @Override  public void config(String key, Integer onoff) {    this.stringRedisTemplate.opsForValue().set(key, String.valueOf(onoff)) ;  }}

这里就提供两种默认的实现。OLU28资讯网——每日最新资讯28at.com

  • 定义切面
@Component@Aspectpublic class ApiSwitchAspect implements ApplicationContextAware {    private ApplicationContext context ;  private final SwitchProperties switchProperties ;  public static final Map<String, Class<? extends SwitchResolver>> MAPPINGS;  static {    // 初始化所有的解析器    Map<String, Class<? extends SwitchResolver>> mappings = new HashMap<>() ;    mappings.put("map", ConcurrentMapResolver.class) ;    mappings.put("redis", RedisResolver.class) ;    MAPPINGS = Collections.unmodifiableMap(mappings) ;  }    public ApiSwitchAspect(SwitchProperties switchProperties) {    this.switchProperties = switchProperties ;  }    @Pointcut("@annotation(apiSwitch)")  private void onoff(ApiSwitch apiSwitch) {}    @Around("onoff(apiSwitch)")  public Object ctl(ProceedingJoinPoint pjp, ApiSwitch apiSwitch) throws Throwable {        // 对应接口开关的key    String key = apiSwitch.key() ;    // 解析器bean的名称    String resolverName = apiSwitch.resolver() ;    // 降级方法名    String fallback = apiSwitch.fallback() ;        SwitchResolver resolver = null ;    // 根据指定的beanName获取具体的解析器;以下都不考虑不存在的情况    if (StringUtils.hasLength(resolverName)) {      resolver = this.context.getBean(resolverName, SwitchResolver.class) ;    } else {      resolver = this.context.getBean(MAPPINGS.get(this.switchProperties.getResolver())) ;    }    // 解析器不存在则直接调用目标接口    if (resolver == null || !resolver.resolver(key)) {      return pjp.proceed() ;    }    // 调用降级的方法;关于降级的方法简单点,都必须在当前接口类中,同时还不考虑方法参数的情况    if (!StringUtils.hasLength(fallback)) {      // 未配置的情况      return "接口不可用" ;    }    Class<?> clazz = pjp.getSignature().getDeclaringType() ;    Method fallbackMethod = clazz.getDeclaredMethod(fallback) ;    return fallbackMethod.invoke(pjp.getTarget()) ;  }  @Override  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {    this.context = applicationContext ;  }  }
  • 修改开关接口
@GetMapping("/onoff/{state}")public Object onoff(String key, @PathVariable("state") Integer state) {  String resolverType = switchProperties.getResolver();  if (!StringUtils.hasLength(resolverType)) {    SwitchResolver bean = this.context.getBean(ApiSwitchAspect.MAPPINGS.get("map")) ;    if (bean instanceof ConcurrentMapResolver resolver) {      resolver.config(key, state) ;    }  } else {    SwitchResolver resolver = this.context.getBean(ApiSwitchAspect.MAPPINGS.get(resolverType)) ;    resolver.config(key, state) ;  }  return "success" ; }

通过该接口修改具体哪个接口的开关状态。(注意:这里有小问题,如果接口上指定了resolver类型且配置文件中指定的类型不一致,就会出现不生效问题。这个问题大家可以自行解决)OLU28资讯网——每日最新资讯28at.com

  • 接下来进行测试
@GetMapping("/q1")@ApiSwitch(key = "swtich$q1", fallback = "q1_fallback", resolver = "redisResolver")public Object q1() {  return "q1" ;}public Object q1_fallback() {  return "接口维护中" ;}

这是完整的配置示例,这里除了key必须外,其它的都可以不填写。OLU28资讯网——每日最新资讯28at.com

具体测试结果就不贴了,大家可以自行测试基于jvm内存和redis的方式。OLU28资讯网——每日最新资讯28at.com

总结:通过上述介绍,我们可以看到使用Spring AOP实现接口的开关功能是一种非常有效的方法。通过定义AOP切面和切入点,我们可以精确地拦截需要控制的方法,并在通知中根据开关状态执行相应的逻辑。这种技术手段有助于提高代码的可维护性和可扩展性,同时提供更好的灵活性和控制性来管理接口的行为OLU28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-34561-0.html优雅实现API接口开关:让你的应用更可控

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: Go 浅析主流日志库:从设计层学习如何集成日志轮转与切割功能

下一篇: 彻底解决Spring Cloud Gateway中Body读取问题

标签:
  • 热门焦点
  • 直屏旗舰来了 iQOO 12和K70 Pro同台竞技

    旗舰机基本上使用的都是双曲面屏幕,这就让很多喜欢直屏的爱好者在苦等一款直屏旗舰,这次,你们等到了。据博主数码闲聊站带来的最新爆料称,Redmi下代旗舰K70 Pro和iQOO 12两款手
  • 一加首款折叠屏!一加Open渲染图出炉:罕见单手可握小尺寸

    8月5日消息,此前就有爆料称,一加首款折叠屏手机将会在第三季度上市,如今随着时间临近,新机的各种消息也开始浮出水面。据悉,这款新机将会被命名为&ldquo;On
  • 三言两语说透设计模式的艺术-单例模式

    写在前面单例模式是一种常用的软件设计模式,它所创建的对象只有一个实例,且该实例易于被外界访问。单例对象由于只有一个实例,所以它可以方便地被系统中的其他对象共享,从而减少
  • 如何正确使用:Has和:Nth-Last-Child

    我们可以用CSS检查,以了解一组元素的数量是否小于或等于一个数字。例如,一个拥有三个或更多子项的grid。你可能会想,为什么需要这样做呢?在某些情况下,一个组件或一个布局可能会
  • 微信语音大揭秘:为什么禁止转发?

    大家好,我是你们的小米。今天,我要和大家聊一个有趣的话题:为什么微信语音不可以转发?这是一个我们经常在日常使用中遇到的问题,也是一个让很多人好奇的问题。让我们一起来揭开这
  • 自动化在DevOps中的力量:简化软件开发和交付

    自动化在DevOps中扮演着重要角色,它提升了DevOps的效能。通过自动化工具和方法,DevOps团队可以实现以下目标:消除手动和重复性任务。简化流程。在整个软件开发生命周期中实现更
  • 新电商三兄弟,“抖快红”成团!

    来源:价值研究所作 者:Hernanderz 随着内容电商的概念兴起,抖音、快手、小红书组成的&ldquo;新电商三兄弟&rdquo;成为业内一股不可忽视的势力,给阿里、京东、拼多多带去了巨大压
  • 华为发布HarmonyOS 4:更好玩、更流畅、更安全

    在8月4日的华为开发者大会2023(HDC.Together)大会上,HarmonyOS 4正式发布。自2019年发布以来,HarmonyOS一直以用户为中心,经历四年多的发展HarmonyOS已
  • iQOO Neo8 Pro抢先上架:首发天玑9200+ 安卓性能之王

    经过了一段时间的密集爆料,昨日iQOO官方如期对外宣布:将于5月23日推出全新的iQOO Neo8系列新品,官方称这是一款拥有旗舰级性能调校的作品。随着发布时
Top