基于Ribbon+RestTemplate的服务调用

简介

SpringCloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。通过SpringCloud 的封装,可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。

注意这里的两个关键词:

  1. 客户端:Ribbon需要将注册中心的服务示例拉去到本地进行缓存,并在本地完成负载均衡的动作,默认使用轮询的方式。
  2. 负载均衡:Ribbon只是进行负载均衡的操作,选取合适的微服务示例来提供给RestTemplate,请求的操作由后者完成。

项目准备

必要准备

引入依赖

如果使用的是eureka client 和 consul client,无须引入依赖。因为在eureka、consul中默认集成了ribbon组件

<!--引入Ribbon依赖--> 
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
   <version>2.2.8.RELEASE</version>
</dependency>

创建RestTemplate配置类

这样我们只需要在需要调用其他服务的控制器中使用@Autowired注解注入即可

@Configuration
public class BeansConfig {

    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

我使用8083、8084、8085同时运行了订单服务来构成订单服务集群。

image.png

编写测试接口

Ribbon提供简单的三种方式来获取配置中心的服务示例或者完成负载均衡

DiscoveryClient

DiscoveryClient可以指定服务的名称来获取配置中心上的实例列表,这个对象是没有实现负载均衡的。

@Slf4j
@RestController
@RequestMapping("/users")
public class UserController {

    /**
     * 服务注册发现客户端对象
     */
    @Autowired
    private DiscoveryClient discoveryClient;

    @Autowired
    private RestTemplate restTemplate;

    /**
     * 获取用户的订单
     */
    @GetMapping("/id/{id}/orders")
    public String getUserOrders(@PathVariable("id") Integer id){
        // 获取注册中心指定服务全部的示例
        List<ServiceInstance> instances = discoveryClient.getInstances("ORDERS");
        instances.forEach(instance -> log.info("DiscoveryClient获取到[ORDERS]服务示例 -> 主机[{}],端口[{}],Uri[{}]", instance.getHost(), instance.getPort(), instance.getUri()));
        // 这里注意,取得是实例列表里面的第一个实例(可能为空),这里可以手动写一个算法,从instances随机获取一个实例
        return restTemplate.getForObject(instances.get(0).getUri+"/orders/uId/"+id, String.class);
    }
}

浏览器访问http://localhost:8082/users/id/2/orders

返回数据:20210726120030X2P8083

image.png

多次请求发现还是返回同样的数据,因为我们没有进行负载均衡,在代码中写死了,instances.get(0).getUri,始终都是向第一个实例发送请求的。

LoadBalancerClient

LoadBalancerClient这是一个负载均衡的客户端对象,使用它提供的choose方法可以使用负载均衡来获取一个服务的实例,这里返回的是单个对象,默认的方式也是沦陷。

@Slf4j
@RestController
@RequestMapping("/users")
public class UserController {

    /**
     * 负载均衡客户端对象
     */
    @Autowired
    private LoadBalancerClient loadBalancerClient;

    @Autowired
    private RestTemplate restTemplate;

    /**
     * 获取用户的订单
     */
    @GetMapping("/id/{id}/orders")
    public String getUserOrders(@PathVariable("id") Integer id){
        // 使用负载均衡获取服务示例对象,默认轮询
        ServiceInstance instance = loadBalancerClient.choose("ORDERS");
        log.info("LoadBalancerClient获取到[ORDERS]服务示例 -> 主机[{}],端口[{}],Uri[{}]", instance.getHost(), instance.getPort(), instance.getUri());

        return restTemplate.getForObject(instance.getUri+"/orders/uId/"+id, String.class);
    }

}

多次在浏览器访问http://localhost:8082/users/id/2/orders

返回数据:

20210726120030X2P8085
20210726120030X2P8084
20210726120030X2P8083

image.png

这里可以看到,这样就实现了负载均衡。

@LoadBalanced

@LoadBalanced注解可以对上面的LoadBalancerClient进行再一次的简化,省掉编写loadBalancerClient.choose("ORDERS");这个语句,将这个对象声明在RestTemplate的生成方法上面可以让生成的对象具有负载均衡的能力。

@Configuration
public class BeansConfig {

    /**
     * LoadBalanced 为restTemplate对象赋予负载均衡的职责
     */
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}
@Slf4j
@RestController
@RequestMapping("/users")
public class UserController {

    @Autowired
    private RestTemplate restTemplate;

    /**
     * 获取用户的订单
     */
    @GetMapping("/id/{id}/orders")
    public String getUserOrders(@PathVariable("id") Integer id){
        // ORDERS为注册中心服务的名称,框架会进行处理
        return restTemplate.getForObject("http://ORDERS/orders/uId/"+id, String.class);
    }
}

多次在浏览器访问http://localhost:8082/users/id/2/orders

返回数据:

20210726120030X2P8085
20210726120030X2P8084
20210726120030X2P8083

这里可以看到,这样也实现了负载均衡。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值