好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

RestTemplate集成Ribbbon的示例代码

上一篇文章我们分析了ribbon的核心原理,接下来我们来看看springcloud是如何集成ribbon的,不同的springcloud的组件(feign,zuul,resttemplate)集成ribbon有所不同,这篇文章先来看看resttemplate。

resttemplate的类图如下

httpaccessor 主要根据 clienthttprequestfactory 创建 clienthttprequest interceptinghttpaccessor 扩展了 httpaccessor ,创建拦截的 interceptingclienthttprequest ,这里会设置拦截器 clienthttprequestinterceptor ,这是集成ribbon的核心,当 resttemplate 发起http请求调用的时候,会先经过拦截器,然后才真正发起http请求。

拦截器 clienthttprequestinterceptor 是如何被设置的呢?在 loadbalancerautoconfiguration 类中,有如下代码:

?

1

2

3

@loadbalanced

@autowired (required = false )

private list<resttemplate> resttemplates = collections.emptylist();

只要加入注解 @loadbalanced 的 resttemplate 会被注入,在没有引入spring retry组件的时候,加载如下配置:

?

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 就被设置了loadbalancerinterceptor,下面来看看整个调用过程

整个过程有点复杂,核心就是经过拦截器loadbalancerinterceptor,通过ribbonloadbalancerclient发起负载均衡调用。ribbonloadbalancerclienti组合了loadbalancer,所以具备了负载均衡的能力,也就是我们在上一篇文章解读的ribbon原理。

图中我们没有画出真正发起http请求的过程,其默认是由 simpleclienthttprequestfactory 创建, clienthttprequestfactory 的类图如下:

从调用时序图上我们看到,开始我们调用的是 interceptingclienthttprequestfactory 来获取 interceptingclienthttprequest ,它们通过组合的方式集成了 clienthttprequestfactory 和拦截器, interceptingclienthttprequest 发起调用的时候委托了其内部类 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();

   }

}

首先会先取出拦截器集合的第一个执行,当拦截器执行完成后,会回调回来,执行else的代码,真正发起http请求,主要有两种方式实现 clienthttprequestfactory 接口:

一种是 simpleclienthttprequestfactory ,使用j2se提供的方式(既java.net包提供的方式)创建底层的http请求连接 一种方式是使用 httpcomponentsclienthttprequestfactory 方式,底层使用httpclient访问远程的http服务,使用httpclient可以配置连接池和证书等信息。

 resttemplate默认是使用simpleclienthttprequestfactory,内部是调用jdk的httpconnection,默认超时为-1,可以这样设置超时时间:

?

1

2

3

4

5

6

7

8

@bean

@loadbalanced

public resttemplate resttemplate() {

   simpleclienthttprequestfactory factory = new simpleclienthttprequestfactory();

   factory.setconnecttimeout( 1000 * 2 ); //连接超时时间

   factory.setreadtimeout( 1000 * 1 ); //读超时时间

   return new resttemplate(factory);

}

使用 httpcomponentsclienthttprequestfactory 方式可以使用连接池(推荐) ,还可以设置重试策略(具体没有研究过)

如果想开启重试机制,我们可以引入spring的retry组件

?

1

2

3

4

5

<dependency>

   <groupid>org.springframework.retry</groupid>

   <artifactid>spring-retry</artifactid>

   <version>版本号</version>

</dependency>

这样springcloud-ribbon就会加重如下配置:

?

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 接口来配置,默认实现类 defaultloadbalancerretryhandler ,如下为默认的配置参数

?

1

2

3

4

5

6

7

8

#最大的重试次数

ribbon.maxautoretries= 0

#最大重试server的个数

ribbon.maxautoretriesnextserver= 1

#是否开启任何异常都重试(默认在get请求下会重试,其他情况不会重试,除非设置为 true )

ribbon.oktoretryonalloperations= false

#指定重试的http状态码

ribbon.retryablestatuscodes= 500 , 501

以上是对全局生效,如果加上 xxx.ribbon.maxautoretries=1 这样只会对某个ribbon客户端生效。maxautoretries和maxautoretriesnextserver是配合使用的,最大重试次数是针对每一个server的,如果设置maxautoretries=1,maxautoretriesnextserver=1这样触发最大重试次数就是4次。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

原文链接:https://segmentfault.com/a/1190000015858648

查看更多关于RestTemplate集成Ribbbon的示例代码的详细内容...

  阅读:46次