前言
隨著使用 spring 進行開發的個人和企業越來越多,spring 也慢慢從一個單一簡潔的小框架變成一個大而全的開源軟件,spring 的邊界不斷的進行擴充,到了后來 spring 幾乎可以做任何事情了,市面上主流的開源軟件、中間件都有 spring 對應組件支持,人們在享用 spring 的這種便利之后,也遇到了一些問題。
斷路器本身是電路上的一種過載保護裝置,當線路中有電器發生短路時,它能夠及時的切斷故障電路以防止嚴重后果發生。通過服務熔斷(也可以稱為斷路)、降級、限流(隔離)、異步rpc等手段控制依賴服務的延遲與失敗,防止整個服務雪崩。一個斷路器可以裝飾并且檢測了一個受保護的功能調用。根據當前的狀態決定調用時被執行還是回退。通常情況下,一個斷路器實現三種類型的狀態:open、half-open以及closed:
- closed狀態的調用被執行,事務度量被存儲,這些度量是實現一個健康策略所必備的。
- 倘若系統健康狀況變差,斷路器就處在open狀態。此種狀態下,所有調用會被立即回退并且不會產生新的調用。open狀態的目的是給服務器端回復和處理問題的時間。
- 一旦斷路器進入一個open狀態,超時計時器開始計時。如果計時器超時,斷路器切換到half-open狀態。在half-open狀態調用間歇性執行以確定問題是否已解決。如果解決,狀態切換回closed狀態。
斷路器背后的基本思想非常簡單。將受保護的函數調用包裝在斷路器對象中,該對象監視故障。一旦故障達到某個閾值,斷路器就會跳閘,并且所有對斷路器的進一步調用都會返回錯誤,而根本不會進行受保護的呼叫。通常,如果斷路器跳閘,您還需要某種監控器警報。
如何快速使用hystrix呢?下面跟著我1234……
1、加入@enablecircuitbreaker注解
1
2
3
4
5
6
7
8
|
@enablecircuitbreaker @springbootapplication @enableeurekaclient @enablefeignclientspublic class droolsappapplication { public static void main(string[] args) { springapplication.run(droolsappapplication. class , args); } } |
hystrix整體執行過程,首先,command會調用run方法,如果run方法超時或者拋出異常,且啟用了降級處理,則調用getfallback方法進行降級;
2、使用@hystrixcommand注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@hystrixcommand (fallbackmethod = "reliable" ) public string readinglist() { for ( int i = 0 ; i < 10 ; i++) { try { thread.sleep( 1000 ); } catch (interruptedexception e) { e.printstacktrace(); } } return "jinpingmei" ; } public string reliable() { return "you love interesting book" ; } |
3、添加引用
1
2
|
compile( "org.springframework.cloud:spring-cloud-starter-hystrix" ) compile( 'org.springframework.cloud:spring-cloud-starter-turbine' ) |
4、設置超時時間
1
|
hystrix.command. default .execution.isolation.thread.timeoutinmilliseconds= 5000 |
執行結果如下:
正常應該返回:
你不要喜歡jinpingmei,要喜歡有意思的書;這樣使用好舒服啊,@enablecircuitbreaker這個注解就這么強大嗎?
hystrixcommandaspect 通過aop攔截所有的@hystrixcommand注解的方法,從而使得@hystrixcommand能夠集成到spring boot中,
hystrixcommandaspect的關鍵代碼如下:
1.方法 hystrixcommandannotationpointcut() 定義攔截注解hystrixcommand
2.方法 hystrixcollapserannotationpointcut()定義攔截注解hystrixcollapser
3.方法methodsannotatedwithhystrixcommand(…)通過@around(…)攔截所有hystrixcommand和hystrixcollapser注解的方法。詳細見方法注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
@aspect public class hystrixcommandaspect { private static final map<hystrixpointcuttype, metaholderfactory> meta_holder_factory_map; static { meta_holder_factory_map = immutablemap.<hystrixpointcuttype, metaholderfactory>builder() .put(hystrixpointcuttype.command, new commandmetaholderfactory()) .put(hystrixpointcuttype.collapser, new collapsermetaholderfactory()) .build(); } @pointcut ( "@annotation(com.netflix.hystrix.contrib.javanica.annotation.hystrixcommand)" ) public void hystrixcommandannotationpointcut() { } @pointcut ( "@annotation(com.netflix.hystrix.contrib.javanica.annotation.hystrixcollapser)" ) public void hystrixcollapserannotationpointcut() { } @around ( "hystrixcommandannotationpointcut() || hystrixcollapserannotationpointcut()" ) public object methodsannotatedwithhystrixcommand( final proceedingjoinpoint joinpoint) throws throwable { method method = getmethodfromtarget(joinpoint); validate.notnull(method, "failed to get method from joinpoint: %s" , joinpoint); if (method.isannotationpresent(hystrixcommand. class ) && method.isannotationpresent(hystrixcollapser. class )) { throw new illegalstateexception( "method cannot be annotated with hystrixcommand and hystrixcollapser " + "annotations at the same time" ); } metaholderfactory metaholderfactory = meta_holder_factory_map.get(hystrixpointcuttype.of(method)); metaholder metaholder = metaholderfactory.create(joinpoint); hystrixinvokable invokable = hystrixcommandfactory.getinstance().create(metaholder); executiontype executiontype = metaholder.iscollapserannotationpresent() ? metaholder.getcollapserexecutiontype() : metaholder.getexecutiontype(); object result; try { result = commandexecutor.execute(invokable, executiontype, metaholder); } catch (hystrixbadrequestexception e) { throw e.getcause(); } return result; } |
那么hystrixcommandaspect是如何初始化,是通過hystrixcircuitbreakerconfiguration實現的
1
2
3
4
5
6
7
|
@configuration public class hystrixcircuitbreakerconfiguration { @bean public hystrixcommandaspect hystrixcommandaspect() { return new hystrixcommandaspect(); } |
那么誰來觸發hystrixcircuitbreakerconfiguration執行初始化
先看spring-cloud-netflix-core**.jar包的spring.factories里有這段配置,是由注解enablecircuitbreaker觸發
1
2
|
org.springframework.cloud.client.circuitbreaker.enablecircuitbreaker=\ org.springframework.cloud.netflix.hystrix.hystrixcircuitbreakerconfiguration |
那么@enablecircuitbreaker如何觸發hystrixcircuitbreakerconfiguration
通過源碼查看,此類通過@import初始化enablecircuitbreakerimportselector類
1
2
3
4
5
6
7
|
@target (elementtype.type) @retention (retentionpolicy.runtime) @documented @inherited @import (enablecircuitbreakerimportselector. class ) public @interface enablecircuitbreaker { } |
enablecircuitbreakerimportselector是springfactoryimportselector子類。此類在初始化后,會執行selectimports(annotationmetadata metadata)的方法。此方法會根據注解啟動的注解(這里指@enablecircuitbreaker)從spring.factories文件中獲取其配置需要初始化@configuration類(這里是org.springframework.cloud.netflix.hystrix.hystrixcircuitbreakerconfiguration),從而最終初始化hystrixcommandaspect 類,從而實現攔截hystrixcommand的功能
以上就是通過@enablecircuitbreake可以開啟hystrix的原理。hystrix用到了觀察者模式abstractcommand.executecommandandobserve()模式,下次我們來深入說一下觀察者模式。歡迎拍磚!
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。
原文鏈接:http://www.cnblogs.com/viaiu/p/9534153.html