上一篇文章我們分析了ribbon的核心原理,接下來我們來看看springcloud是如何集成ribbon的,不同的springcloud的組件(feign,zuul,resttemplate)集成ribbon有所不同,這篇文章先來看看resttemplate。
resttemplate的類圖如下
-
httpaccessor
主要根據(jù)clienthttprequestfactory
創(chuàng)建clienthttprequest
-
interceptinghttpaccessor
擴(kuò)展了httpaccessor
,創(chuàng)建攔截的interceptingclienthttprequest
,這里會(huì)設(shè)置攔截器clienthttprequestinterceptor
,這是集成ribbon的核心,當(dāng)resttemplate
發(fā)起http請(qǐng)求調(diào)用的時(shí)候,會(huì)先經(jīng)過攔截器,然后才真正發(fā)起http請(qǐng)求。
攔截器clienthttprequestinterceptor
是如何被設(shè)置的呢?在loadbalancerautoconfiguration
類中,有如下代碼:
1
2
3
|
@loadbalanced @autowired (required = false ) private list<resttemplate> resttemplates = collections.emptylist(); |
只要加入注解@loadbalanced
的resttemplate
會(huì)被注入,在沒有引入spring retry組件的時(shí)候,加載如下配置:
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
|
@configuration @conditionalonmissingclass ( "org.springframework.retry.support.retrytemplate" ) static class loadbalancerinterceptorconfig { @bean public loadbalancerinterceptor ribboninterceptor( loadbalancerclient loadbalancerclient, loadbalancerrequestfactory requestfactory) { return new loadbalancerinterceptor(loadbalancerclient, requestfactory); } @bean @conditionalonmissingbean public resttemplatecustomizer resttemplatecustomizer( final loadbalancerinterceptor loadbalancerinterceptor) { return new resttemplatecustomizer() { @override public void customize(resttemplate resttemplate) { list<clienthttprequestinterceptor> list = new arraylist<>( resttemplate.getinterceptors()); list.add(loadbalancerinterceptor); resttemplate.setinterceptors(list); } }; } } |
這樣resttemplate
就被設(shè)置了loadbalancerinterceptor,下面來看看整個(gè)調(diào)用過程
整個(gè)過程有點(diǎn)復(fù)雜,核心就是經(jīng)過攔截器loadbalancerinterceptor,通過ribbonloadbalancerclient發(fā)起負(fù)載均衡調(diào)用。ribbonloadbalancerclienti組合了loadbalancer,所以具備了負(fù)載均衡的能力,也就是我們?cè)谏弦黄恼陆庾x的ribbon原理。
圖中我們沒有畫出真正發(fā)起http請(qǐng)求的過程,其默認(rèn)是由simpleclienthttprequestfactory
創(chuàng)建,clienthttprequestfactory
的類圖如下:
從調(diào)用時(shí)序圖上我們看到,開始我們調(diào)用的是interceptingclienthttprequestfactory
來獲取interceptingclienthttprequest
,它們通過組合的方式集成了clienthttprequestfactory
和攔截器,interceptingclienthttprequest
發(fā)起調(diào)用的時(shí)候委托了其內(nèi)部類interceptingrequestexecution
去處理,核心邏輯:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
@override public clienthttpresponse execute(httprequest request, byte [] body) throws ioexception { if ( this .iterator.hasnext()) { clienthttprequestinterceptor nextinterceptor = this .iterator.next(); return nextinterceptor.intercept(request, body, this ); } else { clienthttprequest delegate = requestfactory.createrequest(request.geturi(), request.getmethod()); for (map.entry<string, list<string>> entry : request.getheaders().entryset()) { list<string> values = entry.getvalue(); for (string value : values) { delegate.getheaders().add(entry.getkey(), value); } } if (body.length > 0 ) { streamutils.copy(body, delegate.getbody()); } return delegate.execute(); } } |
首先會(huì)先取出攔截器集合的第一個(gè)執(zhí)行,當(dāng)攔截器執(zhí)行完成后,會(huì)回調(diào)回來,執(zhí)行else的代碼,真正發(fā)起http請(qǐng)求,主要有兩種方式實(shí)現(xiàn)clienthttprequestfactory
接口:
-
一種是
simpleclienthttprequestfactory
,使用j2se提供的方式(既java.net包提供的方式)創(chuàng)建底層的http請(qǐng)求連接 -
一種方式是使用
httpcomponentsclienthttprequestfactory
方式,底層使用httpclient訪問遠(yuǎn)程的http服務(wù),使用httpclient可以配置連接池和證書等信息。
resttemplate默認(rèn)是使用simpleclienthttprequestfactory,內(nèi)部是調(diào)用jdk的httpconnection,默認(rèn)超時(shí)為-1,可以這樣設(shè)置超時(shí)時(shí)間:
1
2
3
4
5
6
7
8
|
@bean @loadbalanced public resttemplate resttemplate() { simpleclienthttprequestfactory factory = new simpleclienthttprequestfactory(); factory.setconnecttimeout( 1000 * 2 ); //連接超時(shí)時(shí)間 factory.setreadtimeout( 1000 * 1 ); //讀超時(shí)時(shí)間 return new resttemplate(factory); } |
使用httpcomponentsclienthttprequestfactory
方式可以使用連接池(推薦) ,還可以設(shè)置重試策略(具體沒有研究過)
如果想開啟重試機(jī)制,我們可以引入spring的retry組件
1
2
3
4
5
|
<dependency> <groupid>org.springframework.retry</groupid> <artifactid>spring-retry</artifactid> <version>版本號(hào)</version> </dependency> |
這樣springcloud-ribbon就會(huì)加重如下配置:
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
43
44
45
|
@configuration @conditionalonclass (retrytemplate. class ) public static class retryautoconfiguration { @bean public retrytemplate retrytemplate() { retrytemplate template = new retrytemplate(); template.setthrowlastexceptiononexhausted( true ); return template; } @bean @conditionalonmissingbean public loadbalancedretrypolicyfactory loadbalancedretrypolicyfactory() { return new loadbalancedretrypolicyfactory.neverretryfactory(); } } @configuration @conditionalonclass (retrytemplate. class ) public static class retryinterceptorautoconfiguration { @bean @conditionalonmissingbean public retryloadbalancerinterceptor ribboninterceptor( loadbalancerclient loadbalancerclient, loadbalancerretryproperties properties, loadbalancedretrypolicyfactory lbretrypolicyfactory, loadbalancerrequestfactory requestfactory) { return new retryloadbalancerinterceptor(loadbalancerclient, properties, lbretrypolicyfactory, requestfactory); } @bean @conditionalonmissingbean public resttemplatecustomizer resttemplatecustomizer( final retryloadbalancerinterceptor loadbalancerinterceptor) { return new resttemplatecustomizer() { @override public void customize(resttemplate resttemplate) { list<clienthttprequestinterceptor> list = new arraylist<>( resttemplate.getinterceptors()); list.add(loadbalancerinterceptor); resttemplate.setinterceptors(list); } }; } } |
1
2
3
4
5
6
|
@bean @conditionalonclass (name = "org.springframework.retry.support.retrytemplate" ) @conditionalonmissingbean public loadbalancedretrypolicyfactory loadbalancedretrypolicyfactory(springclientfactory clientfactory) { return new ribbonloadbalancedretrypolicyfactory(clientfactory); } |
攔截器替換成retryloadbalancerinterceptor
了,這里集成了retry組件retrytemplate。重試策略由retryhandler
接口來配置,默認(rèn)實(shí)現(xiàn)類defaultloadbalancerretryhandler
,如下為默認(rèn)的配置參數(shù)
1
2
3
4
5
6
7
8
|
#最大的重試次數(shù) ribbon.maxautoretries= 0 #最大重試server的個(gè)數(shù) ribbon.maxautoretriesnextserver= 1 #是否開啟任何異常都重試(默認(rèn)在get請(qǐng)求下會(huì)重試,其他情況不會(huì)重試,除非設(shè)置為 true ) ribbon.oktoretryonalloperations= false #指定重試的http狀態(tài)碼 ribbon.retryablestatuscodes= 500 , 501 |
以上是對(duì)全局生效,如果加上xxx.ribbon.maxautoretries=1
這樣只會(huì)對(duì)某個(gè)ribbon客戶端生效。maxautoretries和maxautoretriesnextserver是配合使用的,最大重試次數(shù)是針對(duì)每一個(gè)server的,如果設(shè)置maxautoretries=1,maxautoretriesnextserver=1這樣觸發(fā)最大重試次數(shù)就是4次。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。
原文鏈接:https://segmentfault.com/a/1190000015858648