摘要:得到得到類得到類得到調用的服務名稱檢查和屬性省略部分代碼中的方法里面進行熔斷限流的處理。在的方法中進行的包裝。
Spring Cloud Alibaba Sentinel 除了對 RestTemplate 做了支持,同樣對于 Feign 也做了支持,如果我們要從 Hystrix 切換到 Sentinel 是非常方便的,下面來介紹下如何對 Feign 的支持以及實現原理。
集成 Feign 使用spring-cloud-starter-alibaba-sentinel 的依賴還是要加的,如下:
org.springframework.cloud spring-cloud-starter-alibaba-sentinel 0.2.1.RELEASE
需要在配置文件中開啟 sentinel 對 feign 的支持:
feign.sentinel.enabled=true
然后我們定義自己需要調用的 Feign Client:
@FeignClient(name = "user-service", fallback = UserFeignClientFallback.class) public interface UserFeignClient { @GetMapping("/user/get") public String getUser(@RequestParam("id") Long id); }
定義 fallback 類 UserFeignClientFallback:
@Component public class UserFeignClientFallback implements UserFeignClient { @Override public String getUser(Long id) { return "fallback"; } }
測試代碼:
@Autowired private UserFeignClient userFeignClient; @GetMapping("/testFeign") public String testFeign() { return userFeignClient.getUser(1L); }
你可以將這個 Client 對應的 user-service 停掉,然后就可以看到輸出的內容是 "fallback"
如果要對 Feign 調用做限流,資源名稱的規則是精確到接口的,以我們上面定義的接口來分析,資源名稱就是GET:http://user-service/user/get,至于資源名稱怎么定義的,接下面的源碼分析你就知道了。
原理分析首先看SentinelFeignAutoConfiguration中如何自動配置:
@Bean @Scope("prototype") @ConditionalOnMissingBean @ConditionalOnProperty(name = "feign.sentinel.enabled") public Feign.Builder feignSentinelBuilder() { return SentinelFeign.builder(); }
@ConditionalOnProperty 中 feign.sentinel.enabled 起了決定性作用,這也就是為什么我們需要在配置文件中指定 feign.sentinel.enabled=true。
接下來看 SentinelFeign.builder 里面的實現:
build方法中重新實現了super.invocationHandlerFactory方法,也就是動態代理工廠,構建的是InvocationHandler對象。
build中會獲取Feign Client中的信息,比如fallback,fallbackFactory等,然后創建一個SentinelInvocationHandler,SentinelInvocationHandler繼承了InvocationHandler。
@Override public Feign build() { super.invocationHandlerFactory(new InvocationHandlerFactory() { @Override public InvocationHandler create(Target target, Mapdispatch) { // 得到Feign Client Bean Object feignClientFactoryBean = Builder.this.applicationContext .getBean("&" + target.type().getName()); // 得到fallback類 Class fallback = (Class) getFieldValue(feignClientFactoryBean, "fallback"); // 得到fallbackFactory類 Class fallbackFactory = (Class) getFieldValue(feignClientFactoryBean, "fallbackFactory"); // 得到調用的服務名稱 String name = (String) getFieldValue(feignClientFactoryBean, "name"); Object fallbackInstance; FallbackFactory fallbackFactoryInstance; // 檢查 fallback 和 fallbackFactory 屬性 if (void.class != fallback) { fallbackInstance = getFromContext(name, "fallback", fallback, target.type()); return new SentinelInvocationHandler(target, dispatch, new FallbackFactory.Default(fallbackInstance)); } if (void.class != fallbackFactory) { fallbackFactoryInstance = (FallbackFactory) getFromContext(name, "fallbackFactory", fallbackFactory, FallbackFactory.class); return new SentinelInvocationHandler(target, dispatch, fallbackFactoryInstance); } return new SentinelInvocationHandler(target, dispatch); } // 省略部分代碼 }); super.contract(new SentinelContractHolder(contract)); return super.build(); }
SentinelInvocationHandler中的invoke方法里面進行熔斷限流的處理。
// 得到資源名稱(GET:http://user-service/user/get) String resourceName = methodMetadata.template().method().toUpperCase() + ":" + hardCodedTarget.url() + methodMetadata.template().url(); Entry entry = null; try { ContextUtil.enter(resourceName); entry = SphU.entry(resourceName, EntryType.OUT, 1, args); result = methodHandler.invoke(args); } catch (Throwable ex) { // fallback handle if (!BlockException.isBlockException(ex)) { Tracer.trace(ex); } if (fallbackFactory != null) { try { // 回退處理 Object fallbackResult = fallbackMethodMap.get(method) .invoke(fallbackFactory.create(ex), args); return fallbackResult; } catch (IllegalAccessException e) { // shouldn"t happen as method is public due to being an interface throw new AssertionError(e); } catch (InvocationTargetException e) { throw new AssertionError(e.getCause()); } } // 省略..... }總結
總的來說,這些框架的整合都有相似之處,前面講RestTemplate的整合其實和Ribbon中的@LoadBalanced原理差不多,這次的Feign的整合其實我們從其他框架的整合也是可以參考出來的,最典型的就是Hystrix了。
我們想下Hystrix要對Feign的調用進行熔斷處理,那么肯定是將Feign的請求包裝了HystrixCommand。同樣的道理,我們只要找到Hystrix是如何包裝的,無非就是將Hystrix的代碼換成Sentinel的代碼而已。
InvocationHandlerFactory是用于創建動態代理的工廠,有默認的實現,也有Hystrix的實現feign.hystrix.HystrixFeign。
Feign build(final FallbackFactory> nullableFallbackFactory) { super.invocationHandlerFactory(new InvocationHandlerFactory() { @Override public InvocationHandler create(Target target, Mapdispatch) { return new HystrixInvocationHandler(target, dispatch, setterFactory, nullableFallbackFactory); } }); super.contract(new HystrixDelegatingContract(contract)); return super.build(); }
上面這段代碼是不是跟Sentinel包裝的類似,不同的是Sentinel構造的是SentinelInvocationHandler ,Hystrix構造的是HystrixInvocationHandle。在HystrixInvocationHandler的invoke方法中進行HystrixCommand的包裝。
歡迎加入我的知識星球,一起交流技術,免費學習猿天地的課程(http://cxytiandi.com/course) PS:目前星球中正在星主的帶領下組隊學習Sentinel,等你哦!文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/77682.html
摘要:作用跟一致跟屬性作用一致給設置注解絕對路徑,用于替換服務名。在服務名或與之間默認是,表示當前這個生成的是否是。內部的能獲取服務名信息,的實現類能拿到對應的請求路徑信息。很不幸,這個類也是包級別的類。整合的代碼目前已經在倉庫上,但是沒未發版。 作者 | Spring Cloud Alibaba 高級開發工程師洛夜來自公眾號阿里巴巴中間件投稿 前段時間 Hystrix 宣布不再維護之后(H...
摘要:在之后,也終于發布了最新的版本。該版本距離上一次發布,過去了整整個月下面就隨我一起看看,這個大家期待已久的版本都有哪些內容值得我們關注。如果是用戶,同時也是阿里云這些產品的用戶,那么直接使用還是非常方便的。 在Nacos 1.0.0 Release之后,Spring Cloud Alibaba也終于發布了最新的版本。該版本距離上一次發布,過去了整整4個月!下面就隨我一起看看,這個大家期...
摘要:開發階段很有意義。源碼整合配置文件中添加來開啟編寫類,實現默認用戶遠程調用被限流降級,默認用戶應用定義可以拿到異常信息無法拿到異常信息若初啟動應用,設置流控規則,結果展示如下默認用戶源碼 Sentinel API Github : WIKI Sphu (指明要保護的資源名稱) Tracer (指明調用來源,異常統計接口) ContextUtil(標示進入調用鏈入口) 流控規則(針...
摘要:我沒有能力去控制那些自媒體發布這些不實的內容,但是在我了解的范圍內,還是盡力輸出一些我的理解。 之前我發過一篇《說說我為什么看好Spring Cloud Alibaba》,然后這兩天有網友給我轉了這篇文章《坑爹項目spring-cloud-alibaba,我們也來一個》,問我的看法是怎么樣的,聊天時候簡單說了一下。今天在家休息,抽空整理一下內容,逐點說一下我的看法,主要還是覺得這篇文章...
摘要:之前開放過一臺公益給大家,以方便大家在閱讀我博客中教程時候做實驗。由于目前在連載,所以對應的也部署了一臺,并且也開放出來,給大家學習測試之用。 之前開放過一臺公益Eureka Server給大家,以方便大家在閱讀我博客中教程時候做實驗。由于目前在連載Spring Cloud Alibaba,所以對應的也部署了一臺Nacos,并且也開放出來,給大家學習測試之用。 Nacos控制臺 ...
閱讀 2404·2021-10-14 09:43
閱讀 2435·2021-09-09 09:34
閱讀 1601·2019-08-30 12:57
閱讀 1198·2019-08-29 14:16
閱讀 718·2019-08-26 12:13
閱讀 3201·2019-08-26 11:45
閱讀 2282·2019-08-23 16:18
閱讀 2652·2019-08-23 15:27