最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring AOP實(shí)現(xiàn)斷路器方式

 更新時(shí)間:2025年05月22日 08:53:33   作者:小馬不敲代碼  
這篇文章主要介紹了Spring AOP實(shí)現(xiàn)斷路器方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

環(huán)境:Spring5.3.23

1. 概述

Spring Cloud體系中,斷路器有Hystrix,Resilience4j,Sentinel等組件,它們的核心功能是當(dāng)某個(gè)服務(wù)不可用時(shí),斷路器會(huì)屏蔽相關(guān)故障,返回一個(gè)用戶預(yù)設(shè)的fallback。

具體來說,斷路器有以下一些作用:

  • 阻止故障的向上傳遞:對(duì)服務(wù)的健康狀況進(jìn)行監(jiān)控和防護(hù)。
  • 對(duì)故障快速失敗并積極回復(fù):回退并優(yōu)雅降級(jí)。
  • 提供三種容錯(cuò)方式來幫助達(dá)成目標(biāo):資源隔離,熔斷和降級(jí)。

總的來說,斷路器的核心作用是增強(qiáng)分布式系統(tǒng)的彈性,避免級(jí)聯(lián)故障,以提高系統(tǒng)的整體可用性。

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

我們將通過使用AOP和自定義注解,實(shí)現(xiàn)斷路器功能。根據(jù)自己的需要在關(guān)鍵的方法上添加注解,然后在運(yùn)行時(shí)通過AOP攔截這些注解,并執(zhí)行相應(yīng)的斷路器邏輯。

斷路器的主要作用是防止故障的擴(kuò)散,并保護(hù)系統(tǒng)的穩(wěn)定性。當(dāng)某個(gè)服務(wù)出現(xiàn)故障時(shí),斷路器可以快速中斷與該服務(wù)的連接,并返回一個(gè)預(yù)設(shè)的fallback響應(yīng),從而避免故障對(duì)整個(gè)系統(tǒng)的影響。

通過自定義注解和AOP的結(jié)合,我們可以實(shí)現(xiàn)以下功能:

在需要的接口上添加自定義注解,注解中可以包含與斷路器相關(guān)的配置信息,如:錯(cuò)誤次數(shù),時(shí)間窗口等。

通過AOP攔截這些注解,并在運(yùn)行時(shí)動(dòng)態(tài)地創(chuàng)建斷路器。

當(dāng)服務(wù)調(diào)用時(shí),斷路器會(huì)根據(jù)配置的邏輯判斷是否需要中斷連接或返回fallback響應(yīng)。

如果服務(wù)正常,斷路器將不會(huì)進(jìn)行任何操作;如果服務(wù)故障,斷路器將根據(jù)預(yù)設(shè)的邏輯進(jìn)行處理。

3. 代碼實(shí)現(xiàn)

3.1 自定義注解

AOP只會(huì)攔截該注解的方法或類。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface PackFuse {

  /**降級(jí)方法*/
  String fallback() default "" ;

  /**失敗次數(shù)*/
  int fails() default 5 ;

  /**窗口時(shí)間:s*/
  int windowSize() default 10 ;

}

3.2 自定義斷路器的狀態(tài)

斷路器的狀態(tài)有以下幾種:

  • Closed(關(guān)閉狀態(tài)):默認(rèn)情況下,斷路器處于關(guān)閉狀態(tài),允許遠(yuǎn)程服務(wù)調(diào)用正常進(jìn)行。
  • Open(打開狀態(tài)):當(dāng)遠(yuǎn)程服務(wù)調(diào)用失敗次數(shù)達(dá)到預(yù)設(shè)的閾值時(shí),斷路器會(huì)自動(dòng)打開,中斷與該服務(wù)的所有調(diào)用,并返回fallback響應(yīng)。
  • Half-Open(半開狀態(tài)):在一段時(shí)間后,斷路器會(huì)自動(dòng)從Open狀態(tài)轉(zhuǎn)換到Half-Open狀態(tài)。在Half-Open狀態(tài)下,斷路器會(huì)嘗試少量請(qǐng)求以測(cè)試服務(wù)是否已恢復(fù)。如果測(cè)試請(qǐng)求成功,斷路器將自動(dòng)關(guān)閉并恢復(fù)到Closed狀態(tài);否則,將保持Half-Open狀態(tài),如果超過指定的錯(cuò)誤次數(shù),則再次轉(zhuǎn)變?yōu)镺pen狀態(tài)。

狀態(tài)定義

public enum EnumState {

  CLOSE, HALF_OPEN, OPEN ;
  
}

每個(gè)斷路器都會(huì)自己的狀態(tài)

public class PackFuseState {

  /**當(dāng)前狀態(tài)*/
  private EnumState state = EnumState.CLOSE ;
  /**失敗次數(shù)*/
  private AtomicInteger failCount = new AtomicInteger(0) ;
  /**最大失敗次數(shù)*/
  private int maxFailCount = 5 ;
  /**窗口大??;默認(rèn)每10秒重置*/
  private int windowTime = 10 ;
  
  private static final ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 2, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1)) ;
  
  private Object lock = new Object() ;
  
  public PackFuseState(int maxFailCount, int windowTime) {
    this.maxFailCount = maxFailCount ;
    this.windowTime = windowTime ;
    executor.execute(() -> {
      while(true) {
        if (state == EnumState.CLOSE) {
          try {
            TimeUnit.SECONDS.sleep(windowTime) ;
            if (state == EnumState.CLOSE) {
              failCount.set(0) ;
            }
          } catch (InterruptedException e) {
            e.printStackTrace() ;
          }
        } else {
          synchronized (lock) {
            try {
              lock.wait() ;
            } catch (InterruptedException e) {
              e.printStackTrace() ;
            }
          }
        }
      }
    }) ;
  }
  
  public EnumState getState() {
    return state;
  }
  public void setState(EnumState state) {
    this.state = state;
  }
  public AtomicInteger getFailCount() {
    return failCount;
  }
  public void setFailCount(AtomicInteger failCount) {
    this.failCount = failCount;
  }
  public int getwindowTime() {
    return windowTime;
  }
  public void setwindowTime(int windowTime) {
    this.windowTime = windowTime;
  }
  
  public PackFuseState addFailCount() {
    int count = this.failCount.incrementAndGet() ;
    if (count >= maxFailCount) {
      this.setState(EnumState.OPEN) ;
      executor.execute(() -> {
        try {
          TimeUnit.SECONDS.sleep(windowTime) ;
          setState(EnumState.HALF_OPEN) ;
          failCount.set(0) ;
        } catch (InterruptedException e) {
          e.printStackTrace() ;
        }
      }) ;
    }
    return this ;
  }
  
  public PackFuseState closeState() {
    this.setState(EnumState.CLOSE) ;
    this.failCount.set(0) ;
    return this ;
  }

  public Object getLock() {
    return lock;
  }

}

3.3 切面定義

該切面攔截所有標(biāo)有@PackFuse注解的方法

@Aspect
@Component
public class PackFuseAspect {

  private static final Map<String, PackFuseState> META_HOLDER_MAP = new ConcurrentHashMap<>() ;
  private static final Map<String, Object> FALLBACK = new ConcurrentHashMap<>() ;
  private static final String DEFAULT_RET_DATA = "服務(wù)不可用" ;
  
  @Pointcut("@annotation(fuse)")
  private void fuse(PackFuse fuse) {}
  
  @Around("fuse(fuse)")
  public Object packFuse(ProceedingJoinPoint pjp, PackFuse fuse) {
    MethodSignature joinPointObject = (MethodSignature) pjp.getSignature() ;
    Class<?> targetType = joinPointObject.getDeclaringType() ;
    Method method = joinPointObject.getMethod() ;
    String targetKey = getKey(targetType, method);
    
    String fallback = fuse.fallback() ;
    if (!FALLBACK.containsKey(targetKey)) {
      if (StringUtils.hasLength(fallback)) {
        try {
          Method fallbackMethod = targetType.getDeclaredMethod(fallback) ;
          FALLBACK.put(targetKey, fallbackMethod.invoke(pjp.getTarget())) ;
        } catch (Exception e) {
          e.printStackTrace() ;
        }
      } else {
        FALLBACK.put(targetKey, DEFAULT_RET_DATA) ;
      }
    }
    int fails = fuse.fails() ;
    int windowSize = fuse.windowSize() ;
    
    PackFuseState fuseState = null ;
    try {
      fuseState = META_HOLDER_MAP.computeIfAbsent(targetKey, key -> new PackFuseState(fails, windowSize)) ;
      switch (fuseState.getState()) {
        case CLOSE:
          return pjp.proceed() ;
        case HALF_OPEN:
          Random rd = new Random() ;
          int c = rd.nextInt(fails) ;
          if (c >= (fails / 2)) {
            Object ret = pjp.proceed() ;
            fuseState.closeState() ;
            synchronized (fuseState.getLock()) {
              fuseState.getLock().notifyAll() ; 
            }
            return ret ;
          }
          return FALLBACK.get(targetKey) ;
        case OPEN:
          return FALLBACK.get(targetKey) ;
      }
    } catch (Throwable e) {
      fuseState.addFailCount() ;
    }
    return FALLBACK.get(targetKey) ;
  }
  
  private String getKey(Class<?> targetType, Method method) {
    StringBuilder builder = new StringBuilder();
    builder.append(targetType.getSimpleName());
    builder.append('#').append(method.getName()).append('(');
    if (method.getParameterTypes().length > 0) {
      builder.deleteCharAt(builder.length() - 1);
    }
    return builder.append(')').toString().replaceAll("[^a-zA-Z0-9]", "") ;
  }
  
}

以上就實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的斷路器功能。

通過使用AOP+自定義注解的方式成功地實(shí)現(xiàn)了斷路器功能。這種方法給予了我們很大的靈活性和擴(kuò)展性,可以輕松地對(duì)特定的服務(wù)進(jìn)行故障隔離,避免故障擴(kuò)散,保護(hù)整個(gè)系統(tǒng)的穩(wěn)定性。同時(shí),通過自定義注解,我們能夠清晰地定義斷路器的配置和邏輯,使代碼更易于閱讀和維護(hù)。

這里只是一個(gè)非常簡(jiǎn)單的小例子給大家一個(gè)實(shí)現(xiàn)的思路,大家可以根據(jù)自己的想法或者結(jié)合Hystrix的實(shí)現(xiàn)來豐富功能。

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • java字符串中提取數(shù)字的方法

    java字符串中提取數(shù)字的方法

    Java中提取字符串中的數(shù)字,可以使用正則表達(dá)式或非正則表達(dá)式的方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2023-06-06
  • Java?switch?case語句舉例詳解

    Java?switch?case語句舉例詳解

    這篇文章主要給大家介紹了關(guān)于Java?switch?case語句舉例詳解的相關(guān)資料,switch case語句是一種流程控制語句,用于根據(jù)不同的條件執(zhí)行不同的代碼塊,需要的朋友可以參考下
    2023-10-10
  • openjdk與Oraclejdk的區(qū)別

    openjdk與Oraclejdk的區(qū)別

    這篇文章主要介紹了openjdk與Oraclejdk的區(qū)別,幫助大家更好的了解JAVA,感興趣的朋友可以了解下
    2020-08-08
  • Java設(shè)計(jì)模式之動(dòng)態(tài)代理

    Java設(shè)計(jì)模式之動(dòng)態(tài)代理

    今天小編就為大家分享一篇關(guān)于Java設(shè)計(jì)模式之動(dòng)態(tài)代理,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • Springboot創(chuàng)建時(shí)常用的依賴詳解

    Springboot創(chuàng)建時(shí)常用的依賴詳解

    本文介紹了Spring?Boot項(xiàng)目中常用依賴的配置及作用,涵蓋了父依賴、Web應(yīng)用、測(cè)試、數(shù)據(jù)庫、MyBatis、連接池、JSON處理、Lombok、AOP、校驗(yàn)、監(jiān)控、工具包、打包配置、多配置文件以及熱部署等
    2025-03-03
  • JSP服務(wù)器端和前端出現(xiàn)亂碼問題解決方案

    JSP服務(wù)器端和前端出現(xiàn)亂碼問題解決方案

    這篇文章主要介紹了JSP服務(wù)器端和前端出現(xiàn)亂碼問題解決方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • Spring?Boot深入學(xué)習(xí)數(shù)據(jù)訪問之Spring?Data?JPA與Hibernate的應(yīng)用

    Spring?Boot深入學(xué)習(xí)數(shù)據(jù)訪問之Spring?Data?JPA與Hibernate的應(yīng)用

    Spring?Data?JPA是Spring?Data的子項(xiàng)目,在使用Spring?Data?JPA之前,先了解一下Hibernate,因?yàn)镾pring?Data?JPA是由Hibernate默認(rèn)實(shí)現(xiàn)的
    2022-10-10
  • 淺談java獲取服務(wù)器基本信息

    淺談java獲取服務(wù)器基本信息

    這篇文章主要介紹了java獲取服務(wù)器基本信息,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • java性能優(yōu)化之編譯器版本與平臺(tái)對(duì)應(yīng)關(guān)系

    java性能優(yōu)化之編譯器版本與平臺(tái)對(duì)應(yīng)關(guān)系

    這篇文章主要介紹了java性能優(yōu)化--編譯器版本與平臺(tái)對(duì)應(yīng)關(guān)系,本章節(jié)更加具體化的學(xué)習(xí)編譯器還有哪些可以優(yōu)化的方便,讓你的應(yīng)用展現(xiàn)出更好的性能,需要的朋友可以參考下
    2022-06-06
  • Spring Data JPA踩坑記錄(@id @GeneratedValue)

    Spring Data JPA踩坑記錄(@id @GeneratedValue)

    這篇文章主要介紹了Spring Data JPA踩坑記錄(@id @GeneratedValue),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07

最新評(píng)論

合阳县| 金川县| 莲花县| 呼玛县| 称多县| 乌拉特中旗| 涟源市| 商河县| 陕西省| 赤水市| 定陶县| 彩票| 清镇市| 宣汉县| 鄂州市| 宁阳县| 察雅县| 伊川县| 高邑县| 通辽市| 达州市| 海安县| 巧家县| 亳州市| 镇原县| 刚察县| 略阳县| 嘉荫县| 定安县| 宝丰县| 大姚县| 新沂市| 马山县| 和政县| 南江县| 墨玉县| 阳曲县| 尼木县| 临夏县| 朝阳区| 永顺县|