美文网首页
SpringCloud(二)服务调用 ribbon和feign

SpringCloud(二)服务调用 ribbon和feign

作者: 茧铭 | 来源:发表于2019-04-30 19:35 被阅读0次

在微服务架构中,每个业务模块都被看待为一个独立的服务。服务与服务之间基于Restful 风格的接口相互通信。Spring cloud有两种调用方式,分别是使用ribbon + restTemplate 和 feign。

1、事先准备(可快速略过)

在开始之前,我在本地写了一个Order服务,两个Product服务,并实现了一些逻辑


jiaxini.img

以findByProductIdIn接口为例,这个接口是供订单调用的接口。逻辑是订单服务拿到几种产品的productId的List集合,商品服务查询这几种商品的详情并返回结果。首先我在postman测试一下这个接口的功能。(但我自己非常不推荐传入集合作为参数的操作)


request
response

2、Ribbon + Rest 服务消费

在消费服务的order项目中加入依赖

<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

这儿我分别用三种方式去实现接口的调用;

方式一:利用restTemplate

我之前写过一些介绍restTemplate的基本使用的文章,这里可以直接拿来使用

RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:3003/product/findByProductIdIn";
List<String> stringList = Arrays.asList("8216e50c-3826-4a2f-bb54-3a4b6f408b10", "4ea84cda-fca8-443b-a957-51c621bc8330");
List list = restTemplate.postForObject(url, stringList, List.class);
log.info(list.toString());

这样做的弊端是我的Url比较固定,ip和端口号集中,我只能通过一些restTemplate提供的添加参数的方法去实现逻辑。在微服务的情况下,如果一台服务器部署了两个微服务,就只能去找某一个了,也没有了高可用。

方法二:使用loadBalancerClient类
    @Autowired
    private LoadBalancerClient loadBalancerClient;

    @GetMapping(value = "/method2")
    public void useLoadBalancerClient(){
        RestTemplate restTemplate = new RestTemplate();
        //发现服务
        ServiceInstance serviceInstance = loadBalancerClient.choose("product");
        String url = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/product/findByProductIdIn";
        List<String> stringList = Arrays.asList("8216e50c-3826-4a2f-bb54-3a4b6f408b10",
                                     "4ea84cda-fca8-443b-a957-51c621bc8330");
        List list = restTemplate.postForObject(url, stringList, List.class);
        log.info(list.toString());
    }

这样做对比直接使用restTemplate固定Url的形式,有一个好处就是首先利用LoadBalancerClient 去发现serviceId为“product”的服务,然后再取这个服务的host和port去拼接请求。这样做就避免了写死ip和端口的情况。再者在LoadBalancerClient中实际上是引入了一种 IRULE 的东西,它定义了如何去使用服务的规则。比如说product提供了多个服务,可以选择使用轮询、随机等方式去访问服务,具体情况具体实现。

源码阅读:
ServiceInstance serviceInstance = loadBalancerClient.choose("product");





可以发现springCloud默认使用了RoundRobinRule去定义调用规则,也就是轮询,如果过服务会按照1->2->3->1->2->3->1这样的方式去依次调用我们指定的服务。就像下图的结果这样,3003和3004是商品服务的端口。

当然除了轮询之外还有一些别的emmmm(并不认识,但很感人)的规则,当然也可以自己实现IRULE并注册一个自定义的方式到Bean里。

切换这个Rule也比较简单,这个类里给我们了一个setRule的方法,将要用的IRULE的Bean注册到里面应该就能生效了,这里我并没有尝试,有兴趣的大哥麻烦试一下并传唤我。不过我在网上看到另外一种更改的方法,即直接修改配置。如下图所示
PRODUCT是服务名serviceId
IRULE类是全路径

方法三:

先创建一个配置类,定义RestTemplate的Bean,加入注解@LoadBalanced

@Configuration
public class RestTemplateConfig {

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

    @GetMapping(value = "/method3")
    public void useLoadBalancedAnnotation(){
        List<String> stringList = Arrays.asList("8216e50c-3826-4a2f-bb54-3a4b6f408b10", "4ea84cda-fca8-443b-a957-51c621bc8330");
        // 第一个product是服务名serviceId,第二个是请求路径的一部分
        List result = restTemplate.postForObject("http://product/product/findByProductIdIn", stringList, List.class);
        log.info(result.toString());
    }
请求成功

这个注解的原理和方法二类似,它的底层用的就是LoadBalancerClient实现。

3、Feign

feign是在ribbon的基础上做了一些改进。它采用接口的方式, 只需要创建一个接口,然后在上面添加注解即可 ,将需要调用的其他服务的方法定义成抽象方法即可, 不需要自己构建http请求。
个人选择使用feign的原因是因为feign接口较ribbon拼接请求而言,更加的直观地展示了需要的参数和返回类型,而接口调用的方式,会让我觉得它就是一个service,我可以去正常调用它的接口。

首先加入依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

在启动类上加入注解

/**  basePackages 限定包路径  */
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = "com.jiaxini.order.feign")
public class OrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }
}

feign接口类编写

@FeignClient(value = "product")
public interface ProductFeign {

    /**  查询根据idList查询商品列表  */
    @PostMapping("/product/findByProductIdIn")
    public List<ProductInfoSimplifyVO> findByProductIdIn(@RequestBody List<String> idList);

    /**  订单减库:根据商品Id减去一定数量的库存  */
    @PostMapping("/product/reduceProductStock")
    public boolean reduceProductStock(@RequestBody List<ReduseProductForm> reduseProductFormList);

}

@FeignClient:表明这是一个feign接口类
value:填写调用服务的serviceId
接口方法则与调用接口一致(方法名可以自定义)

具体使用

打完收工!

相关文章

网友评论

      本文标题:SpringCloud(二)服务调用 ribbon和feign

      本文链接:https://www.haomeiwen.com/subject/msnynqtx.html