日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當(dāng)前位置:首頁(yè) > 科技  > 軟件

優(yōu)雅實(shí)現(xiàn)API接口開(kāi)關(guān):讓你的應(yīng)用更可控

來(lái)源: 責(zé)編: 時(shí)間:2023-11-28 09:32:33 235觀(guān)看
導(dǎo)讀環(huán)境:SpringBoot2.7.121. 概述本文將介紹如何為API接口動(dòng)態(tài)添加開(kāi)關(guān)功能。通過(guò)這個(gè)功能,我們可以控制API接口的正常訪(fǎng)問(wèn)或顯示提示信息。這有助于在開(kāi)發(fā)和維護(hù)過(guò)程中更好地管理和控制API接口的行為。通過(guò)使用開(kāi)關(guān)功能,我

環(huán)境:SpringBoot2.7.1214728資訊網(wǎng)——每日最新資訊28at.com

1. 概述

本文將介紹如何為API接口動(dòng)態(tài)添加開(kāi)關(guān)功能。通過(guò)這個(gè)功能,我們可以控制API接口的正常訪(fǎng)問(wèn)或顯示提示信息。這有助于在開(kāi)發(fā)和維護(hù)過(guò)程中更好地管理和控制API接口的行為。通過(guò)使用開(kāi)關(guān)功能,我們可以輕松地在不同情況下調(diào)整接口的行為,提高系統(tǒng)的靈活性和可維護(hù)性。14728資訊網(wǎng)——每日最新資訊28at.com

為什么要給API接口添加開(kāi)關(guān)功能呢?從以下幾方面考慮:14728資訊網(wǎng)——每日最新資訊28at.com

  1. 靈活性和可擴(kuò)展性:我們可以根據(jù)需要?jiǎng)討B(tài)地控制API接口的行為。這使得在面對(duì)不同場(chǎng)景和需求時(shí),可以更加靈活地調(diào)整接口的行為,而無(wú)需對(duì)代碼進(jìn)行修改。
  2. 安全性和控制:有時(shí),我們可能不希望在特定情況下API接口被正常訪(fǎng)問(wèn),例如在測(cè)試、維護(hù)或敏感數(shù)據(jù)訪(fǎng)問(wèn)等場(chǎng)景下。通過(guò)關(guān)閉開(kāi)關(guān)并顯示提示信息,我們可以對(duì)用戶(hù)進(jìn)行必要的通知和引導(dǎo),確保接口不被未經(jīng)授權(quán)的訪(fǎng)問(wèn)。
  3. 錯(cuò)誤處理和日志記錄:當(dāng)API接口出現(xiàn)錯(cuò)誤或異常時(shí),關(guān)閉開(kāi)關(guān)并顯示提示信息可以幫助我們更好地追蹤和記錄問(wèn)題。這對(duì)于后續(xù)的問(wèn)題排查和系統(tǒng)優(yōu)化非常有幫助。
  4. 系統(tǒng)監(jiān)控和管理:通過(guò)監(jiān)控開(kāi)關(guān)狀態(tài)的變化,我們可以了解系統(tǒng)的運(yùn)行狀況,以及用戶(hù)對(duì)API接口的使用情況。這有助于進(jìn)行系統(tǒng)性能優(yōu)化和資源管理。
  5. 用戶(hù)體驗(yàn):在某些情況下,當(dāng)API接口不可用或需要維護(hù)時(shí),向用戶(hù)顯示友好的提示信息可以避免用戶(hù)感到困惑或帶來(lái)不必要的困擾。同時(shí),提前通知用戶(hù)也體現(xiàn)了對(duì)用戶(hù)體驗(yàn)的關(guān)注。
  6. 合規(guī)性和隱私保護(hù):在涉及敏感數(shù)據(jù)或受限制的API接口中,通過(guò)關(guān)閉開(kāi)關(guān)并顯示提示信息,可以確保遵守相關(guān)法規(guī)和隱私政策,對(duì)數(shù)據(jù)進(jìn)行適當(dāng)?shù)墓芾砗捅Wo(hù)。

2. 實(shí)現(xiàn)方案

首先,定義一個(gè)AOP切面(Aspect),該切面負(fù)責(zé)控制接口(Controller)的開(kāi)關(guān)行為。14728資訊網(wǎng)——每日最新資訊28at.com

在切面中,我們可以使用Spring AOP的切入點(diǎn)(Pointcut)來(lái)指定需要攔截的方法。一旦方法被攔截,我們可以在切面的通知(Advice)中定義相應(yīng)的默認(rèn)行為。接下來(lái)我們將一步一步的實(shí)現(xiàn)接口開(kāi)關(guān)功能。14728資訊網(wǎng)——每日最新資訊28at.com

  • 自定義注解
@Target({ElementType.TYPE, ElementType.METHOD})public @interface ApiSwitch {  /**接口對(duì)應(yīng)的key,通過(guò)可以該key查詢(xún)接口是否關(guān)閉*/  String key() default "" ;    /**解析器beanName,通過(guò)具體的實(shí)現(xiàn)獲取key對(duì)應(yīng)的值*/  String resolver() default "" ;    /**開(kāi)啟后降級(jí)方法名*/  String fallback() default "" ;  }
  • 定義解析器接口
public interface SwitchResolver {  boolean resolver(String key) ;    public void config(String key, Integer onoff) ;  }
  • 接口默認(rèn)實(shí)現(xiàn)
@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實(shí)現(xiàn)
@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)) ;  }}

這里就提供兩種默認(rèn)的實(shí)現(xiàn)。14728資訊網(wǎng)——每日最新資訊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 {        // 對(duì)應(yīng)接口開(kāi)關(guān)的key    String key = apiSwitch.key() ;    // 解析器bean的名稱(chēng)    String resolverName = apiSwitch.resolver() ;    // 降級(jí)方法名    String fallback = apiSwitch.fallback() ;        SwitchResolver resolver = null ;    // 根據(jù)指定的beanName獲取具體的解析器;以下都不考慮不存在的情況    if (StringUtils.hasLength(resolverName)) {      resolver = this.context.getBean(resolverName, SwitchResolver.class) ;    } else {      resolver = this.context.getBean(MAPPINGS.get(this.switchProperties.getResolver())) ;    }    // 解析器不存在則直接調(diào)用目標(biāo)接口    if (resolver == null || !resolver.resolver(key)) {      return pjp.proceed() ;    }    // 調(diào)用降級(jí)的方法;關(guān)于降級(jí)的方法簡(jiǎn)單點(diǎn),都必須在當(dāng)前接口類(lèi)中,同時(shí)還不考慮方法參數(shù)的情況    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 ;  }  }
  • 修改開(kāi)關(guān)接口
@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" ; }

通過(guò)該接口修改具體哪個(gè)接口的開(kāi)關(guān)狀態(tài)。(注意:這里有小問(wèn)題,如果接口上指定了resolver類(lèi)型且配置文件中指定的類(lèi)型不一致,就會(huì)出現(xiàn)不生效問(wèn)題。這個(gè)問(wèn)題大家可以自行解決)14728資訊網(wǎng)——每日最新資訊28at.com

  • 接下來(lái)進(jìn)行測(cè)試
@GetMapping("/q1")@ApiSwitch(key = "swtich$q1", fallback = "q1_fallback", resolver = "redisResolver")public Object q1() {  return "q1" ;}public Object q1_fallback() {  return "接口維護(hù)中" ;}

這是完整的配置示例,這里除了key必須外,其它的都可以不填寫(xiě)。14728資訊網(wǎng)——每日最新資訊28at.com

具體測(cè)試結(jié)果就不貼了,大家可以自行測(cè)試基于jvm內(nèi)存和redis的方式。14728資訊網(wǎng)——每日最新資訊28at.com

總結(jié):通過(guò)上述介紹,我們可以看到使用Spring AOP實(shí)現(xiàn)接口的開(kāi)關(guān)功能是一種非常有效的方法。通過(guò)定義AOP切面和切入點(diǎn),我們可以精確地?cái)r截需要控制的方法,并在通知中根據(jù)開(kāi)關(guān)狀態(tài)執(zhí)行相應(yīng)的邏輯。這種技術(shù)手段有助于提高代碼的可維護(hù)性和可擴(kuò)展性,同時(shí)提供更好的靈活性和控制性來(lái)管理接口的行為14728資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-34561-0.html優(yōu)雅實(shí)現(xiàn)API接口開(kāi)關(guān):讓你的應(yīng)用更可控

聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: Go 淺析主流日志庫(kù):從設(shè)計(jì)層學(xué)習(xí)如何集成日志輪轉(zhuǎn)與切割功能

下一篇: 徹底解決Spring Cloud Gateway中Body讀取問(wèn)題

標(biāo)簽:
  • 熱門(mén)焦點(diǎn)
Top 主站蜘蛛池模板: 洱源县| 泰来县| 平凉市| 乌恰县| 叶城县| 云林县| 富裕县| 惠州市| 璧山县| 桃园县| 阿拉善盟| 屯昌县| 福清市| 巴马| 兴仁县| 丰原市| 利川市| 巴中市| 北海市| 抚宁县| 汽车| 平邑县| 都江堰市| 临朐县| 内乡县| 巍山| 巴里| 贵港市| 清河县| 修水县| 黄龙县| 多伦县| 恩平市| 营山县| 二连浩特市| 呼伦贝尔市| 重庆市| 南康市| 铜陵市| 龙井市| 天门市|