在Spring Cloud Commons中提供了大量的与服务治理相关的抽象接口,包括 DiscoveryClient
、这里我们即将介绍的 LoadBalancerClient
等。对于这些接口的定义我们在上一篇介绍服务注册与发现时已经说过,Spring Cloud做这一层抽象,很好的解耦了服务治理体系,使得我们可以轻易的替换不同的服务治理设施。
从 LoadBalancerClient
接口的命名中,我们就知道这是一个负载均衡客户端的抽象定义,下面我们就看看如何使用Spring Cloud提供的负载均衡器客户端接口来实现服务的消费。
下面的例子,我们将利用上一篇中构建的eureka-server作为服务注册中心、eureka-client作为服务提供者作为基础。
eureka-consumer
。并在 pom.xml
中引入依赖(这里省略了parent和dependencyManagement的配置): <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies> 复制代码
配置 application.properties
,指定eureka注册中心的地址:
spring.application.name=eureka-consumer server.port=2101 eureka.client.serviceUrl.defaultZone=http://localhost:1001/eureka/ 复制代码
创建应用主类。初始化 RestTemplate
,用来真正发起REST请求。 @EnableDiscoveryClient
注解用来将当前应用加入到服务治理体系中。
@EnableDiscoveryClient @SpringBootApplication public class Application { @Bean public RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { new SpringApplicationBuilder(Application.class).web(true).run(args); } } 复制代码
创建一个接口用来消费eureka-client提供的接口:
@RestController public class DcController { @Autowired LoadBalancerClient loadBalancerClient; @Autowired RestTemplate restTemplate; @GetMapping("/consumer") public String dc() { ServiceInstance serviceInstance = loadBalancerClient.choose("eureka-client"); String url = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/dc"; System.out.println(url); return restTemplate.getForObject(url, String.class); } } 复制代码
可以看到这里,我们注入了 LoadBalancerClient
和 RestTemplate
,并在 /consumer
接口的实现中,先通过 loadBalancerClient
的 choose
函数来负载均衡的选出一个 eureka-client
的服务实例,这个服务实例的基本信息存储在 ServiceInstance
中,然后通过这些对象中的信息拼接出访问 /dc
接口的详细地址,最后再利用 RestTemplate
对象实现对服务提供者接口的调用。
在完成了上面你的代码编写之后,读者可以将eureka-server、eureka-client、eureka-consumer都启动起来,然后访问 http://localhost:2101/consumer ,来跟踪观察eureka-consumer服务是如何消费eureka-client服务的 /dc
接口的。
通过上面的学习,我们已经学会如何通过 LoadBalancerClient
接口来获取某个服务的具体实例,并根据实例信息来发起服务接口消费请求。但是这样的做法需要我们手工的去编写服务选取、链接拼接等繁琐的工作,对于开发人员来说非常的不友好。所以,下来我们看看Spring Cloud中针对客户端负载均衡的工具包:Spring Cloud Ribbon。
Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。它是一个基于HTTP和TCP的客户端负载均衡器。它可以通过在客户端中配置ribbonServerList来设置服务端列表去轮询访问以达到均衡负载的作用。
当Ribbon与Eureka联合使用时,ribbonServerList会被DiscoveryEnabledNIWSServerList重写,扩展成从Eureka注册中心中获取服务实例列表。同时它也会用NIWSDiscoveryPing来取代IPing,它将职责委托给Eureka来确定服务端是否已经启动。
而当Ribbon与Consul联合使用时,ribbonServerList会被ConsulServerList来扩展成从Consul获取服务实例列表。同时由ConsulPing来作为IPing接口的实现。
我们在使用Spring Cloud Ribbon的时候,不论是与Eureka还是Consul结合,都会在引入Spring Cloud Eureka或Spring Cloud Consul依赖的时候通过自动化配置来加载上述所说的配置内容,所以我们可以快速在Spring Cloud中实现服务间调用的负载均衡。
下面我们通过具体的例子来看看如何使用Spring Cloud Ribbon来实现服务的调用以及客户端均衡负载。
下面的例子,我们将利用之前构建的 eureka-server
作为服务注册中心、 eureka-client
作为服务提供者作为基础。而基于Spring Cloud Ribbon实现的消费者,我们可以根据 eureka-consumer
实现的内容进行简单改在就能完成,具体步骤如下:
根据 eureka-consumer
复制一个服务消费者工程,命名为: eureka-consumer-ribbon
。在 pom.xml
中增加下面的依赖:
<dependencies> ... <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> </dependency> </dependencies> 复制代码
修改应用主类。为 RestTemplate
增加 @LoadBalanced
注解:
@SpringBootApplication @EnableDiscoveryClient public class EurekaConsumerApplication { @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(EurekaConsumerApplication.class, args); } } 复制代码
修改Controller。去掉原来通过 LoadBalancerClient
选取实例和拼接URL的步骤,直接通过RestTemplate发起请求。
@RestController public class DcController { @Autowired RestTemplate restTemplate; @GetMapping("/consumer") public String dc() { return restTemplate.getForObject("http://eureka-client/dc", String.class); } } 复制代码
可以看到这里,我们除了去掉了原来与 LoadBalancerClient
相关的逻辑之外,对于 RestTemplate
的使用,我们的第一个url参数有一些特别。这里请求的host位置并没有使用一个具体的IP地址和端口的形式,而是采用了服务名的方式组成。那么这样的请求为什么可以调用成功呢?因为Spring Cloud Ribbon有一个拦截器,它能够在这里进行实际调用的时候,自动的去选取服务实例,并将实际要请求的IP地址和端口替换这里的服务名,从而完成服务接口的调用。
在完成了上面你的代码编写之后,读者可以将eureka-server、eureka-client、eureka-consumer-ribbon都启动起来,然后访问 http://localhost:2101/consumer ,来跟踪观察eureka-consumer-ribbon服务是如何消费eureka-client服务的 /dc
接口的,并且也可以通过启动多个eureka-client服务来观察其负载均衡的效果。
Spring Cloud Feign是一套基于Netflix Feign实现的声明式服务调用客户端。它使得编写Web服务客户端变得更加简单。我们只需要通过创建接口并用注解来配置它既可完成对Web服务接口的绑定。它具备可插拔的注解支持,包括Feign注解、JAX-RS注解。它也支持可插拔的编码器和解码器。Spring Cloud Feign还扩展了对Spring MVC注解的支持,同时还整合了Ribbon和Eureka来提供均衡负载的HTTP客户端实现。
下面,我们通过一个例子来展现Feign如何方便的声明对eureka-client服务的定义和调用。
下面的例子,我们将利用之前构建的 eureka-server
作为服务注册中心、 eureka-client
作为服务提供者作为基础。而基于Spring Cloud Ribbon实现的消费者,我们可以根据 eureka-consumer
实现的内容进行简单改在就能完成,具体步骤如下:
根据 eureka-consumer
复制一个服务消费者工程,命名为: eureka-consumer-feign
。在 pom.xml
中增加下面的依赖:
<dependencies> ... <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency> </dependencies> 复制代码
修改应用主类。通过 @EnableFeignClients
注解开启扫描Spring Cloud Feign客户端的功能:
@EnableFeignClients @EnableDiscoveryClient @SpringBootApplication public class Application { public static void main(String[] args) { new SpringApplicationBuilder(Application.class).web(true).run(args); } } 复制代码
创建一个Feign的客户端接口定义。使用 @FeignClient
注解来指定这个接口所要调用的服务名称,接口中定义的各个函数使用Spring MVC的注解就可以来绑定服务提供方的REST接口,比如下面就是绑定 eureka-client
服务的 /dc
接口的例子:
@FeignClient("eureka-client") public interface DcClient { @GetMapping("/dc") String consumer(); } 复制代码
修改Controller。通过定义的feign客户端来调用服务提供方的接口:
@RestController public class DcController { @Autowired DcClient dcClient; @GetMapping("/consumer") public String dc() { return dcClient.consumer(); } } 复制代码
通过Spring Cloud Feign来实现服务调用的方式更加简单了,通过 @FeignClient
定义的接口来统一的生命我们需要依赖的微服务接口。而在具体使用的时候就跟调用本地方法一点的进行调用即可。由于Feign是基于Ribbon实现的,所以它自带了客户端负载均衡功能,也可以通过Ribbon的IRule进行策略扩展。另外,Feign还整合的Hystrix来实现服务的容错保护,在Dalston版本中,Feign的Hystrix默认是关闭的。
在完成了上面你的代码编写之后,读者可以将eureka-server、eureka-client、eureka-consumer-feign都启动起来,然后访问 http://localhost:2101/consumer ,来跟踪观察eureka-consumer-feign服务是如何消费eureka-client服务的 /dc
接口的,并且也可以通过启动多个eureka-client服务来观察其负载均衡的效果。
还可参考spring cloud