一个大型的系统由多个微服务模块组成,我们一般可以通过内部接口调用的形式(服务A提供一个接口,服务B通过HTTP请求调用服务A的接口)实现各模块之间的通信。为了简化开发,SpringCloud集成了Spring Cloud Netflix Ribbon和Spring Cloud OpenFeign,两个组件都支持通过HTTP请求不同的服务。
举个例子,用户模块和评论模块,当查询评论列表时需要返回用户的基本信息(昵称、头像等),直接利用SQL语句关联查询是可以实现该需求的,但是耦合性较强,亦不利于扩展。用户信息应由用户模块提供,这时就需要用户模块提供接口,评论模块调用此接口,从而拿到用户数据。
本文将简要介绍Spring Cloud Netflix Ribbon,借此引出 Sping Cloud OpenFeign,并详细介绍其用法。
Spring Cloud Netflix Ribbon的使用Spring Cloud Netflix Ribbon(即 Ribbon )是Spring Cloud Netflix的一个子项目,它提供了HTTP客户端和TCP客户端,用于支持各服务间的通信并且拥有负载均衡能力。
Ribbon 的一个核心概念是命名的客户端。每一个负载均衡器都是Ribbon组件的一部分,它们在需要的时候一起工作,并且和远程服务器通信。
在 Spring Cloud工程中引用Ribbon非常简单,只需要在pom.xml中添加以下依赖:
org.springframework.cloudspring-cloud-starter-netflix-ribbon
只要添加了上述依赖,该工程就拥有了Ribbon的HTTP远程调用能力。Ribbon通过RestTemplate类调用远程服务器,因此我们还需要注入RestTemplate类,在 webConfig 类中添加以下代码:
@Bean @LoadBalanced public RestTemplate restTemplate(){i return new RestTemplate(); }
除了读者已经熟悉的@Bean 注解外,还多了一个@LoadBalanced注解,只有增加该注解,Ribbon才会启用负载均衡。接下来演示通过comment服务远程调用TEST服务。
首先,在comment工程下创建TestServiceRibbon接口和TestServiceImplRibbon类,该类用于远程调用TEST服务的其中一个接口,编写代码如下:
public interface TestServiceRibbon { String test(; } @service public class TestServicelmplRibbon implements TestServiceRibbon { @Autowired private RestTemplate restTemplate; @Override public string test() { return restTemplate.postForEntity("http://TEST/test" ,null,String.class).getBody(); } }
我们可以看到,代码注入了webConfig 配置的 RestTemplate类,然后通过RestTemplate 的postForEntity方法调用TEST服务的test接口,并通过getBody方法返回结果。
然后,创建控制器类,并编写如下代码:
@RequestMapping( "ribbon") @RestController public class TestcontrollerRibbon i @Autowired TestServiceRibbon testserviceRibbon;@RequestMapping( "test") private String test(){ return testServiceRibbon.test(); } }
提供上述控制器的目的是更方便地测试Ribbon能否成功调用TEST服务及其负载均衡能力,当然也可以直接用单元测试,但是无法看到负载均衡效果。
我们可以分别启动register、config、comment、test 工程,其中 test工程分别以9999和 9998端口启动两次,浏览器多次访问地址localhost:8203/ribbon/test,可以看到分别打印出端口9999和 9998,说明Ribbon负载均衡已生效。
正如上面所说,如果不添加@LoadBalancer 注解,则无法使用负载均衡功能,并且 postForEntity传入的地址无法直接使用服务名TEST,会报如图11-1所示的错误。
因为失去了负载均衡能力,RestTemplate不会拉取注册表信息,而是直接调用传人的地址,因而提示TEST是未知主机 ( host)。要解决这个问题,需要将 http:/TEST/test 替换成具体的地址,如http://localhost:9999/test。
接着介绍postForEntity方法,顾名思义,该方法以POST方式请求HTTP地址并返回相应的实体对象。其中第一个参数为请求地址,第二个参数为请求参数,第三个参数为要转成的实体类。RestTemplate对应的方法还有getForEntity,很明显该方法是GET请求。
通过Ribbon的学习,读者可以了解到服务间是如何通信的。但Ribbon也有自身的缺陷,它通过RestTemplate 去调用HTTP接口,看起来就是一个HTTP远程调用,和整个微服务工程没有多大关系,我们完全可以自己通过远程HTTP请求实现。因此,Spring Cloud又集成了OpenFeign,它的使用更加优雅,像是工程自己的方法。